Page MenuHomeFreeBSD

D6967.diff
No OneTemporary

D6967.diff

Index: head/sys/dev/iwm/if_iwm.c
===================================================================
--- head/sys/dev/iwm/if_iwm.c
+++ head/sys/dev/iwm/if_iwm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */
+/* $OpenBSD: if_iwm.c,v 1.42 2015/05/30 02:49:23 deraadt Exp $ */
/*
* Copyright (c) 2014 genua mbh <info@genua.de>
@@ -173,11 +173,23 @@
100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
149, 153, 157, 161, 165
};
-#define IWM_NUM_2GHZ_CHANNELS 14
-
_Static_assert(nitems(iwm_nvm_channels) <= IWM_NUM_CHANNELS,
"IWM_NUM_CHANNELS is too small");
+const uint8_t iwm_nvm_channels_8000[] = {
+ /* 2.4 GHz */
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ /* 5 GHz */
+ 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
+ 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+ 149, 153, 157, 161, 165, 169, 173, 177, 181
+};
+_Static_assert(nitems(iwm_nvm_channels_8000) <= IWM_NUM_CHANNELS_8000,
+ "IWM_NUM_CHANNELS_8000 is too small");
+
+#define IWM_NUM_2GHZ_CHANNELS 14
+#define IWM_N_HW_ADDR_MASK 0xF
+
/*
* XXX For now, there's simply a fixed set of rate table entries
* that are populated.
@@ -205,6 +217,11 @@
#define IWM_RIDX_IS_CCK(_i_) ((_i_) < IWM_RIDX_OFDM)
#define IWM_RIDX_IS_OFDM(_i_) ((_i_) >= IWM_RIDX_OFDM)
+struct iwm_nvm_section {
+ uint16_t length;
+ uint8_t *data;
+};
+
static int iwm_store_cscheme(struct iwm_softc *, const uint8_t *, size_t);
static int iwm_firmware_store_section(struct iwm_softc *,
enum iwm_ucode_type,
@@ -242,27 +259,45 @@
static int iwm_nic_rx_init(struct iwm_softc *);
static int iwm_nic_tx_init(struct iwm_softc *);
static int iwm_nic_init(struct iwm_softc *);
-static void iwm_enable_txq(struct iwm_softc *, int, int);
+static int iwm_enable_txq(struct iwm_softc *, int, int, int);
static int iwm_post_alive(struct iwm_softc *);
static int iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, uint16_t,
uint16_t, uint8_t *, uint16_t *);
static int iwm_nvm_read_section(struct iwm_softc *, uint16_t, uint8_t *,
- uint16_t *);
+ uint16_t *, size_t);
static uint32_t iwm_eeprom_channel_flags(uint16_t);
static void iwm_add_channel_band(struct iwm_softc *,
- struct ieee80211_channel[], int, int *, int, int,
+ struct ieee80211_channel[], int, int *, int, size_t,
const uint8_t[]);
static void iwm_init_channel_map(struct ieee80211com *, int, int *,
struct ieee80211_channel[]);
static int iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *,
- const uint16_t *, const uint16_t *, uint8_t,
- uint8_t);
-struct iwm_nvm_section;
+ const uint16_t *, const uint16_t *,
+ const uint16_t *, const uint16_t *,
+ const uint16_t *);
+static void iwm_set_hw_address_8000(struct iwm_softc *,
+ struct iwm_nvm_data *,
+ const uint16_t *, const uint16_t *);
+static int iwm_get_sku(const struct iwm_softc *, const uint16_t *,
+ const uint16_t *);
+static int iwm_get_nvm_version(const struct iwm_softc *, const uint16_t *);
+static int iwm_get_radio_cfg(const struct iwm_softc *, const uint16_t *,
+ const uint16_t *);
+static int iwm_get_n_hw_addrs(const struct iwm_softc *,
+ const uint16_t *);
+static void iwm_set_radio_cfg(const struct iwm_softc *,
+ struct iwm_nvm_data *, uint32_t);
static int iwm_parse_nvm_sections(struct iwm_softc *,
struct iwm_nvm_section *);
static int iwm_nvm_init(struct iwm_softc *);
+static int iwm_firmware_load_sect(struct iwm_softc *, uint32_t,
+ const uint8_t *, uint32_t);
static int iwm_firmware_load_chunk(struct iwm_softc *, uint32_t,
const uint8_t *, uint32_t);
+static int iwm_load_firmware_7000(struct iwm_softc *, enum iwm_ucode_type);
+static int iwm_load_cpu_sections_8000(struct iwm_softc *,
+ struct iwm_fw_sects *, int , int *);
+static int iwm_load_firmware_8000(struct iwm_softc *, enum iwm_ucode_type);
static int iwm_load_firmware(struct iwm_softc *, enum iwm_ucode_type);
static int iwm_start_fw(struct iwm_softc *, enum iwm_ucode_type);
static int iwm_send_tx_ant_cfg(struct iwm_softc *, uint8_t);
@@ -297,10 +332,8 @@
struct ieee80211_node *, int);
static int iwm_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
-static void iwm_mvm_add_sta_cmd_v6_to_v5(struct iwm_mvm_add_sta_cmd_v6 *,
- struct iwm_mvm_add_sta_cmd_v5 *);
static int iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *,
- struct iwm_mvm_add_sta_cmd_v6 *,
+ struct iwm_mvm_add_sta_cmd_v7 *,
int *);
static int iwm_mvm_sta_send_to_fw(struct iwm_softc *, struct iwm_node *,
int);
@@ -321,6 +354,13 @@
static int iwm_media_change(struct ifnet *);
static int iwm_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void iwm_endscan_cb(void *, int);
+static void iwm_mvm_fill_sf_command(struct iwm_softc *,
+ struct iwm_sf_cfg_cmd *,
+ struct ieee80211_node *);
+static int iwm_mvm_sf_config(struct iwm_softc *, enum iwm_sf_state);
+static int iwm_send_bt_init_conf(struct iwm_softc *);
+static int iwm_send_update_mcc_cmd(struct iwm_softc *, const char *);
+static void iwm_mvm_tt_tx_backoff(struct iwm_softc *, uint32_t);
static int iwm_init_hw(struct iwm_softc *);
static void iwm_init(struct iwm_softc *);
static void iwm_start(struct iwm_softc *);
@@ -331,10 +371,12 @@
static const char *
iwm_desc_lookup(uint32_t);
static void iwm_nic_error(struct iwm_softc *);
+static void iwm_nic_umac_error(struct iwm_softc *);
#endif
static void iwm_notif_intr(struct iwm_softc *);
static void iwm_intr(void *);
static int iwm_attach(device_t);
+static int iwm_is_valid_ether_addr(uint8_t *);
static void iwm_preinit(void *);
static int iwm_detach_local(struct iwm_softc *sc, int);
static void iwm_init_task(void *);
@@ -477,6 +519,12 @@
}
fw->fw_fp = fwp;
+ /* (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
*/
@@ -490,7 +538,10 @@
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_fp->datasize - sizeof(*uhdr);
@@ -527,7 +578,8 @@
sc->sc_capa_max_probe_len
= le32toh(*(const 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) {
IWM_DPRINTF(sc, IWM_DEBUG_FIRMWARE_TLV,
"%s: IWM_UCODE_TLV_PROBE_MAX_LEN "
"ridiculous\n", __func__);
@@ -578,7 +630,8 @@
goto parse_out;
}
break;
- case IWM_UCODE_TLV_NUM_OF_CPU:
+ case IWM_UCODE_TLV_NUM_OF_CPU: {
+ uint32_t num_cpu;
if (tlv_len != sizeof(uint32_t)) {
device_printf(sc->sc_dev,
"%s: IWM_UCODE_TLV_NUM_OF_CPU: tlv_len (%d) < sizeof(uint32_t)\n",
@@ -587,15 +640,16 @@
error = EINVAL;
goto parse_out;
}
- if (le32toh(*(const uint32_t*)tlv_data) != 1) {
+ num_cpu = le32toh(*(const uint32_t *)tlv_data);
+ if (num_cpu < 1 || num_cpu > 2) {
device_printf(sc->sc_dev,
- "%s: driver supports "
- "only TLV_NUM_OF_CPU == 1",
+ "%s: Driver supports only 1 or 2 CPUs\n",
__func__);
error = EINVAL;
goto parse_out;
}
break;
+ }
case IWM_UCODE_TLV_SEC_RT:
if ((error = iwm_firmware_store_section(sc,
IWM_UCODE_TYPE_REGULAR, tlv_data, tlv_len)) != 0) {
@@ -657,11 +711,80 @@
le32toh(*(const 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: {
+ const struct iwm_ucode_api *api;
+ if (tlv_len != sizeof(*api)) {
+ error = EINVAL;
+ goto parse_out;
+ }
+ api = (const struct iwm_ucode_api *)tlv_data;
+ /* Flags may exceed 32 bits in future firmware. */
+ if (le32toh(api->api_index) > 0) {
+ device_printf(sc->sc_dev,
+ "unsupported API index %d\n",
+ le32toh(api->api_index));
+ goto parse_out;
+ }
+ sc->sc_ucode_api = le32toh(api->api_flags);
+ break;
+ }
+
+ case IWM_UCODE_TLV_ENABLED_CAPABILITIES: {
+ const struct iwm_ucode_capa *capa;
+ int idx, i;
+ if (tlv_len != sizeof(*capa)) {
+ error = EINVAL;
+ goto parse_out;
+ }
+ capa = (const struct iwm_ucode_capa *)tlv_data;
+ idx = le32toh(capa->api_index);
+ if (idx > howmany(IWM_NUM_UCODE_TLV_CAPA, 32)) {
+ device_printf(sc->sc_dev,
+ "unsupported API index %d\n", idx);
+ goto parse_out;
+ }
+ for (i = 0; i < 32; i++) {
+ if ((le32toh(capa->api_capa) & (1U << 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(*(const 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(((const uint32_t *)tlv_data)[0]),
+ le32toh(((const uint32_t *)tlv_data)[1]),
+ le32toh(((const uint32_t *)tlv_data)[2]));
+ break;
+
default:
device_printf(sc->sc_dev,
"%s: unknown firmware section %d, abort\n",
@@ -710,7 +833,7 @@
if (error != 0)
return;
KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs));
- *(bus_addr_t *)arg = segs[0].ds_addr;
+ *(bus_addr_t *)arg = segs[0].ds_addr;
}
static int
@@ -720,6 +843,7 @@
int error;
dma->tag = NULL;
+ dma->map = NULL;
dma->size = size;
dma->vaddr = NULL;
@@ -739,14 +863,16 @@
if (error != 0) {
bus_dmamem_free(dma->tag, dma->vaddr, dma->map);
dma->vaddr = NULL;
- goto fail;
+ goto fail;
}
bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE);
return 0;
-fail: iwm_dma_contig_free(dma);
+fail:
+ iwm_dma_contig_free(dma);
+
return error;
}
@@ -764,7 +890,6 @@
bus_dma_tag_destroy(dma->tag);
dma->tag = NULL;
}
-
}
/* fwmem is used to load firmware onto the card */
@@ -901,7 +1026,7 @@
static void
iwm_disable_rx_dma(struct iwm_softc *sc)
{
-
+ /* XXX conditional nic locks are stupid */
/* XXX print out if we can't lock the NIC? */
if (iwm_nic_lock(sc)) {
/* XXX handle if RX stop doesn't finish? */
@@ -915,6 +1040,11 @@
{
/* Reset the ring state */
ring->cur = 0;
+
+ /*
+ * The hw rx ring index in shared memory must also be cleared,
+ * otherwise the discrepancy can cause reprocessing chaos.
+ */
memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat));
}
@@ -1125,6 +1255,7 @@
/* Set physical address of ICT table (4KB aligned). */
IWM_WRITE(sc, IWM_CSR_DRAM_INT_TBL_REG,
IWM_CSR_DRAM_INT_TBL_ENABLE
+ | IWM_CSR_DRAM_INIT_TBL_WRITE_POINTER
| IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK
| sc->ict_dma.paddr >> IWM_ICT_PADDR_SHIFT);
@@ -1217,7 +1348,7 @@
*/
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
@@ -1263,9 +1394,11 @@
* (PCIe power is lost before PERST# is asserted), causing ME FW
* to lose ownership and not being able to obtain it back.
*/
- iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG,
- IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
- ~IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
+ iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG,
+ IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+ ~IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ }
}
static int
@@ -1295,16 +1428,12 @@
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);
@@ -1318,7 +1447,7 @@
* Thus sayeth el jefe (iwlwifi) via a comment:
*
* This value should initially be 0 (before preparing any
- * RBs), should be 8 after preparing the first 8 RBs (for example)
+ * RBs), should be 8 after preparing the first 8 RBs (for example)
*/
IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, 8);
@@ -1354,6 +1483,9 @@
qid, txq->desc,
(unsigned long) (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;
@@ -1365,7 +1497,8 @@
int error;
iwm_apm_init(sc);
- iwm_set_pwr(sc);
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000)
+ iwm_set_pwr(sc);
iwm_mvm_nic_config(sc);
@@ -1392,52 +1525,79 @@
IWM_MVM_TX_FIFO_BK,
};
-static void
-iwm_enable_txq(struct iwm_softc *sc, int qid, int fifo)
+static int
+iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo)
{
if (!iwm_nic_lock(sc)) {
device_printf(sc->sc_dev,
"%s: cannot enable txq %d\n",
__func__,
qid);
- return; /* XXX return EBUSY */
+ return EBUSY;
}
- /* unactivate before configuration */
- iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
- (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE)
- | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+ IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0);
- if (qid != IWM_MVM_CMD_QUEUE) {
- iwm_set_bits_prph(sc, IWM_SCD_QUEUECHAIN_SEL, (1 << qid));
- }
+ if (qid == IWM_MVM_CMD_QUEUE) {
+ /* unactivate before configuration */
+ iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
+ (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE)
+ | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+
+ iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid));
+
+ iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0);
+
+ iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0);
+ /* Set scheduler window size and frame limit. */
+ iwm_write_mem32(sc,
+ sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) +
+ sizeof(uint32_t),
+ ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+ IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+ ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+ IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+ iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
+ (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+ (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) |
+ (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) |
+ IWM_SCD_QUEUE_STTS_REG_MSK);
+ } else {
+ struct iwm_scd_txq_cfg_cmd cmd;
+ int error;
- iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid));
+ iwm_nic_unlock(sc);
- IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0);
- iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.scd_queue = qid;
+ cmd.enable = 1;
+ cmd.sta_id = sta_id;
+ cmd.tx_fifo = fifo;
+ cmd.aggregate = 0;
+ cmd.window = IWM_FRAME_LIMIT;
+
+ error = iwm_mvm_send_cmd_pdu(sc, IWM_SCD_QUEUE_CFG, IWM_CMD_SYNC,
+ sizeof(cmd), &cmd);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "cannot enable txq %d\n", qid);
+ return error;
+ }
+
+ if (!iwm_nic_lock(sc))
+ return EBUSY;
+ }
- 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);
+ iwm_write_prph(sc, IWM_SCD_EN_CTRL,
+ iwm_read_prph(sc, IWM_SCD_EN_CTRL) | qid);
iwm_nic_unlock(sc);
- IWM_DPRINTF(sc, IWM_DEBUG_XMIT,
- "%s: enabled txq %d FIFO %d\n",
+ IWM_DPRINTF(sc, IWM_DEBUG_XMIT, "%s: enabled txq %d FIFO %d\n",
__func__, qid, fifo);
+
+ return 0;
}
static int
@@ -1445,16 +1605,16 @@
{
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)) {
+ base = iwm_read_prph(sc, IWM_SCD_SRAM_BASE_ADDR);
+ if (sc->sched_base != base) {
device_printf(sc->sc_dev,
- "%s: sched addr mismatch",
- __func__);
- error = EINVAL;
- goto out;
+ "%s: sched addr mismatch: alive: 0x%x prph: 0x%x\n",
+ __func__, sc->sched_base, base);
}
iwm_ict_reset(sc);
@@ -1474,8 +1634,15 @@
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);
@@ -1490,11 +1657,13 @@
IWM_FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
/* Enable L1-Active */
- iwm_clear_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
- IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) {
+ iwm_clear_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
+ IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ }
out:
- iwm_nic_unlock(sc);
+ iwm_nic_unlock(sc);
return error;
}
@@ -1508,17 +1677,25 @@
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,
+ IWM_NVM_SECTION_TYPE_HW_8000,
+ IWM_NVM_SECTION_TYPE_MAC_OVERRIDE,
+ IWM_NVM_SECTION_TYPE_PHY_SKU,
};
/* 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
+
static int
iwm_nvm_read_chunk(struct iwm_softc *sc, uint16_t section,
uint16_t offset, uint16_t length, uint8_t *data, uint16_t *len)
@@ -1538,20 +1715,24 @@
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) {
+ device_printf(sc->sc_dev,
+ "Could not send NVM_ACCESS command (error=%d)\n", ret);
return ret;
+ }
pkt = cmd.resp_pkt;
if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) {
device_printf(sc->sc_dev,
- "%s: Bad return from IWM_NVM_ACCES_COMMAND (0x%08X)\n",
- __func__, pkt->hdr.flags);
+ "Bad return from IWM_NVM_ACCES_COMMAND (0x%08X)\n",
+ pkt->hdr.flags);
ret = EIO;
goto exit;
}
@@ -1564,17 +1745,25 @@
offset_read = le16toh(nvm_resp->offset);
resp_data = nvm_resp->data;
if (ret) {
- device_printf(sc->sc_dev,
- "%s: NVM access command failed with status %d\n",
- __func__, ret);
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "NVM access command failed with status %d\n", ret);
ret = EINVAL;
goto exit;
}
if (offset_read != offset) {
device_printf(sc->sc_dev,
- "%s: NVM ACCESS response with invalid offset %d\n",
- __func__, offset_read);
+ "NVM ACCESS response with invalid offset %d\n",
+ offset_read);
+ ret = EINVAL;
+ goto exit;
+ }
+
+ if (bytes_read > length) {
+ device_printf(sc->sc_dev,
+ "NVM ACCESS response with too much data "
+ "(%d bytes requested, %zd bytes received)\n",
+ length, bytes_read);
ret = EINVAL;
goto exit;
}
@@ -1589,7 +1778,7 @@
/*
* Reads an NVM section completely.
- * NICs prior to 7000 family doesn't have a real NVM, but just read
+ * NICs prior to 7000 family don't have a real NVM, but just read
* section 0 which is the EEPROM. Because the EEPROM reading is unlimited
* by uCode, we need to manually check in this case that we don't
* overflow and try to read more than the EEPROM size.
@@ -1599,32 +1788,34 @@
*/
static 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;
+
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "reading NVM section %d\n", section);
- /* Set nvm section read length */
- length = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE;
+ chunklen = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE;
*len = 0;
- /* Read the NVM until exhausted (reading less than requested) */
- while (seglen == length) {
+ /* Read NVM chunks until exhausted (reading less than requested) */
+ while (seglen == chunklen && *len < max_len) {
error = iwm_nvm_read_chunk(sc,
- section, *len, length, data, &seglen);
+ section, *len, chunklen, data, &seglen);
if (error) {
- device_printf(sc->sc_dev,
- "Cannot read NVM from section "
- "%d offset %d, length %d\n",
- section, *len, length);
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "Cannot read from NVM section "
+ "%d at offset %d\n", section, *len);
return error;
}
*len += seglen;
}
IWM_DPRINTF(sc, IWM_DEBUG_RESET,
- "NVM section %d read completed\n", section);
- return 0;
+ "NVM section %d read completed (%d bytes, error=%d)\n",
+ section, *len, error);
+ return error;
}
/*
@@ -1634,7 +1825,7 @@
/* iwlwifi/iwl-nvm-parse.c */
/* NVM offsets (in words) definitions */
-enum wkp_nvm_offsets {
+enum iwm_nvm_offsets {
/* NVM HW-Section offset (in words) definitions */
IWM_HW_ADDR = 0x15,
@@ -1651,6 +1842,32 @@
IWM_XTAL_CALIB = 0x316 - IWM_NVM_CALIB_SECTION
};
+enum iwm_8000_nvm_offsets {
+ /* NVM HW-Section offset (in words) definitions */
+ IWM_HW_ADDR0_WFPM_8000 = 0x12,
+ IWM_HW_ADDR1_WFPM_8000 = 0x16,
+ IWM_HW_ADDR0_PCIE_8000 = 0x8A,
+ IWM_HW_ADDR1_PCIE_8000 = 0x8E,
+ IWM_MAC_ADDRESS_OVERRIDE_8000 = 1,
+
+ /* NVM SW-Section offset (in words) definitions */
+ IWM_NVM_SW_SECTION_8000 = 0x1C0,
+ IWM_NVM_VERSION_8000 = 0,
+ IWM_RADIO_CFG_8000 = 0,
+ IWM_SKU_8000 = 2,
+ IWM_N_HW_ADDRS_8000 = 3,
+
+ /* NVM REGULATORY -Section offset (in words) definitions */
+ IWM_NVM_CHANNELS_8000 = 0,
+ IWM_NVM_LAR_OFFSET_8000_OLD = 0x4C7,
+ IWM_NVM_LAR_OFFSET_8000 = 0x507,
+ IWM_NVM_LAR_ENABLED_8000 = 0x7,
+
+ /* NVM calibration section offset (in words) definitions */
+ IWM_NVM_CALIB_SECTION_8000 = 0x2B8,
+ IWM_XTAL_CALIB_8000 = 0x316 - IWM_NVM_CALIB_SECTION_8000
+};
+
/* SKU Capabilities (actual values from NVM definition) */
enum nvm_sku_bits {
IWM_NVM_SKU_CAP_BAND_24GHZ = (1 << 0),
@@ -1667,6 +1884,13 @@
#define IWM_NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
#define IWM_NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+#define IWM_NVM_RF_CFG_FLAVOR_MSK_8000(x) (x & 0xF)
+#define IWM_NVM_RF_CFG_DASH_MSK_8000(x) ((x >> 4) & 0xF)
+#define IWM_NVM_RF_CFG_STEP_MSK_8000(x) ((x >> 8) & 0xF)
+#define IWM_NVM_RF_CFG_TYPE_MSK_8000(x) ((x >> 12) & 0xFFF)
+#define IWM_NVM_RF_CFG_TX_ANT_MSK_8000(x) ((x >> 24) & 0xF)
+#define IWM_NVM_RF_CFG_RX_ANT_MSK_8000(x) ((x >> 28) & 0xF)
+
#define DEFAULT_MAX_TX_POWER 16
/**
@@ -1718,7 +1942,8 @@
static void
iwm_add_channel_band(struct iwm_softc *sc, struct ieee80211_channel chans[],
- int maxchans, int *nchans, int ch_idx, int ch_num, const uint8_t bands[])
+ int maxchans, int *nchans, int ch_idx, size_t ch_num,
+ const uint8_t bands[])
{
const uint16_t * const nvm_ch_flags = sc->sc_nvm.nvm_ch_flags;
uint32_t nflags;
@@ -1728,7 +1953,10 @@
for (; ch_idx < ch_num; ch_idx++) {
ch_flags = le16_to_cpup(nvm_ch_flags + ch_idx);
- ieee = iwm_nvm_channels[ch_idx];
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000)
+ ieee = iwm_nvm_channels[ch_idx];
+ else
+ ieee = iwm_nvm_channels_8000[ch_idx];
if (!(ch_flags & IWM_NVM_CHANNEL_VALID)) {
IWM_DPRINTF(sc, IWM_DEBUG_EEPROM,
@@ -1760,6 +1988,7 @@
struct iwm_softc *sc = ic->ic_softc;
struct iwm_nvm_data *data = &sc->sc_nvm;
uint8_t bands[IEEE80211_MODE_BYTES];
+ size_t ch_num;
memset(bands, 0, sizeof(bands));
/* 1-13: 11b/g channels. */
@@ -1774,51 +2003,182 @@
IWM_NUM_2GHZ_CHANNELS - 1, IWM_NUM_2GHZ_CHANNELS, bands);
if (data->sku_cap_band_52GHz_enable) {
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000)
+ ch_num = nitems(iwm_nvm_channels);
+ else
+ ch_num = nitems(iwm_nvm_channels_8000);
memset(bands, 0, sizeof(bands));
setbit(bands, IEEE80211_MODE_11A);
iwm_add_channel_band(sc, chans, maxchans, nchans,
- IWM_NUM_2GHZ_CHANNELS, nitems(iwm_nvm_channels), bands);
+ IWM_NUM_2GHZ_CHANNELS, ch_num, bands);
}
}
+static void
+iwm_set_hw_address_8000(struct iwm_softc *sc, struct iwm_nvm_data *data,
+ const uint16_t *mac_override, const uint16_t *nvm_hw)
+{
+ const uint8_t *hw_addr;
+
+ if (mac_override) {
+ static const uint8_t reserved_mac[] = {
+ 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00
+ };
+
+ hw_addr = (const uint8_t *)(mac_override +
+ IWM_MAC_ADDRESS_OVERRIDE_8000);
+
+ /*
+ * Store the MAC address from MAO section.
+ * No byte swapping is required in MAO section
+ */
+ IEEE80211_ADDR_COPY(data->hw_addr, hw_addr);
+
+ /*
+ * Force the use of the OTP MAC address in case of reserved MAC
+ * address in the NVM, or if address is given but invalid.
+ */
+ if (!IEEE80211_ADDR_EQ(reserved_mac, hw_addr) &&
+ !IEEE80211_ADDR_EQ(ieee80211broadcastaddr, data->hw_addr) &&
+ iwm_is_valid_ether_addr(data->hw_addr) &&
+ !IEEE80211_IS_MULTICAST(data->hw_addr))
+ return;
+
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "%s: mac address from nvm override section invalid\n",
+ __func__);
+ }
+
+ if (nvm_hw) {
+ /* read the mac address from WFMP registers */
+ uint32_t mac_addr0 =
+ htole32(iwm_read_prph(sc, IWM_WFMP_MAC_ADDR_0));
+ uint32_t mac_addr1 =
+ htole32(iwm_read_prph(sc, IWM_WFMP_MAC_ADDR_1));
+
+ hw_addr = (const uint8_t *)&mac_addr0;
+ data->hw_addr[0] = hw_addr[3];
+ data->hw_addr[1] = hw_addr[2];
+ data->hw_addr[2] = hw_addr[1];
+ data->hw_addr[3] = hw_addr[0];
+
+ hw_addr = (const uint8_t *)&mac_addr1;
+ data->hw_addr[4] = hw_addr[1];
+ data->hw_addr[5] = hw_addr[0];
+
+ return;
+ }
+
+ device_printf(sc->sc_dev, "%s: mac address not found\n", __func__);
+ memset(data->hw_addr, 0, sizeof(data->hw_addr));
+}
+
+static int
+iwm_get_sku(const struct iwm_softc *sc, const uint16_t *nvm_sw,
+ const uint16_t *phy_sku)
+{
+ if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + IWM_SKU);
+
+ return le32_to_cpup((const uint32_t *)(phy_sku + IWM_SKU_8000));
+}
+
+static int
+iwm_get_nvm_version(const struct iwm_softc *sc, const uint16_t *nvm_sw)
+{
+ if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + IWM_NVM_VERSION);
+ else
+ return le32_to_cpup((const uint32_t *)(nvm_sw +
+ IWM_NVM_VERSION_8000));
+}
+
+static int
+iwm_get_radio_cfg(const struct iwm_softc *sc, const uint16_t *nvm_sw,
+ const uint16_t *phy_sku)
+{
+ if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + IWM_RADIO_CFG);
+
+ return le32_to_cpup((const uint32_t *)(phy_sku + IWM_RADIO_CFG_8000));
+}
+
+static int
+iwm_get_n_hw_addrs(const struct iwm_softc *sc, const uint16_t *nvm_sw)
+{
+ int n_hw_addr;
+
+ if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000)
+ return le16_to_cpup(nvm_sw + IWM_N_HW_ADDRS);
+
+ n_hw_addr = le32_to_cpup((const uint32_t *)(nvm_sw + IWM_N_HW_ADDRS_8000));
+
+ return n_hw_addr & IWM_N_HW_ADDR_MASK;
+}
+
+static void
+iwm_set_radio_cfg(const struct iwm_softc *sc, struct iwm_nvm_data *data,
+ uint32_t radio_cfg)
+{
+ if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) {
+ data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK(radio_cfg);
+ data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK(radio_cfg);
+ data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK(radio_cfg);
+ data->radio_cfg_pnum = IWM_NVM_RF_CFG_PNUM_MSK(radio_cfg);
+ return;
+ }
+
+ /* set the radio configuration for family 8000 */
+ data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK_8000(radio_cfg);
+ data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK_8000(radio_cfg);
+ data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK_8000(radio_cfg);
+ data->radio_cfg_pnum = IWM_NVM_RF_CFG_FLAVOR_MSK_8000(radio_cfg);
+ data->valid_tx_ant = IWM_NVM_RF_CFG_TX_ANT_MSK_8000(radio_cfg);
+ data->valid_rx_ant = IWM_NVM_RF_CFG_RX_ANT_MSK_8000(radio_cfg);
+}
+
static 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_hw, const uint16_t *nvm_sw,
+ 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[IEEE80211_ADDR_LEN];
- uint16_t radio_cfg, sku;
+ uint32_t sku, radio_cfg;
- data->nvm_version = le16_to_cpup(nvm_sw + IWM_NVM_VERSION);
+ data->nvm_version = iwm_get_nvm_version(sc, nvm_sw);
- radio_cfg = le16_to_cpup(nvm_sw + IWM_RADIO_CFG);
- data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK(radio_cfg);
- data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK(radio_cfg);
- data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK(radio_cfg);
- data->radio_cfg_pnum = IWM_NVM_RF_CFG_PNUM_MSK(radio_cfg);
+ radio_cfg = iwm_get_radio_cfg(sc, nvm_sw, phy_sku);
+ iwm_set_radio_cfg(sc, data, radio_cfg);
- sku = le16_to_cpup(nvm_sw + IWM_SKU);
+ sku = iwm_get_sku(sc, nvm_sw, phy_sku);
data->sku_cap_band_24GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_24GHZ;
data->sku_cap_band_52GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_52GHZ;
data->sku_cap_11n_enable = 0;
- 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);
+ data->n_hw_addrs = iwm_get_n_hw_addrs(sc, nvm_sw);
/* The byte order is little endian 16 bit, meaning 214365 */
- IEEE80211_ADDR_COPY(hw_addr, nvm_hw + IWM_HW_ADDR);
- data->hw_addr[0] = hw_addr[1];
- data->hw_addr[1] = hw_addr[0];
- data->hw_addr[2] = hw_addr[3];
- data->hw_addr[3] = hw_addr[2];
- data->hw_addr[4] = hw_addr[5];
- data->hw_addr[5] = hw_addr[4];
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
+ IEEE80211_ADDR_COPY(hw_addr, nvm_hw + IWM_HW_ADDR);
+ data->hw_addr[0] = hw_addr[1];
+ data->hw_addr[1] = hw_addr[0];
+ data->hw_addr[2] = hw_addr[3];
+ data->hw_addr[3] = hw_addr[2];
+ data->hw_addr[4] = hw_addr[5];
+ data->hw_addr[5] = hw_addr[4];
+ } else {
+ iwm_set_hw_address_8000(sc, data, mac_override, nvm_hw);
+ }
- memcpy(data->nvm_ch_flags, &nvm_sw[IWM_NVM_CHANNELS],
- sizeof(data->nvm_ch_flags));
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
+ memcpy(data->nvm_ch_flags, &nvm_sw[IWM_NVM_CHANNELS],
+ IWM_NUM_CHANNELS * sizeof(uint16_t));
+ } else {
+ memcpy(data->nvm_ch_flags, &regulatory[IWM_NVM_CHANNELS_8000],
+ IWM_NUM_CHANNELS_8000 * sizeof(uint16_t));
+ }
data->calib_version = 255; /* TODO:
this value will prevent some checks from
failing, we need to check if this
@@ -1832,30 +2192,61 @@
* END NVM PARSE
*/
-struct iwm_nvm_section {
- uint16_t length;
- uint8_t *data;
-};
-
static 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, *regulatory, *mac_override, *phy_sku;
/* Checking for required sections */
- if (!sections[IWM_NVM_SECTION_TYPE_SW].data ||
- !sections[IWM_NVM_SECTION_TYPE_HW].data) {
- device_printf(sc->sc_dev,
- "%s: Can't parse empty NVM sections\n",
- __func__);
- return ENOENT;
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
+ if (!sections[IWM_NVM_SECTION_TYPE_SW].data ||
+ !sections[IWM_NVM_SECTION_TYPE_HW].data) {
+ device_printf(sc->sc_dev,
+ "Can't parse empty OTP/NVM sections\n");
+ return ENOENT;
+ }
+
+ hw = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_HW].data;
+ } else if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) {
+ /* SW and REGULATORY sections are mandatory */
+ if (!sections[IWM_NVM_SECTION_TYPE_SW].data ||
+ !sections[IWM_NVM_SECTION_TYPE_REGULATORY].data) {
+ device_printf(sc->sc_dev,
+ "Can't parse empty OTP/NVM sections\n");
+ return ENOENT;
+ }
+ /* MAC_OVERRIDE or at least HW section must exist */
+ if (!sections[IWM_NVM_SECTION_TYPE_HW_8000].data &&
+ !sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data) {
+ device_printf(sc->sc_dev,
+ "Can't parse mac_address, empty sections\n");
+ return ENOENT;
+ }
+
+ /* PHY_SKU section is mandatory in B0 */
+ if (!sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data) {
+ device_printf(sc->sc_dev,
+ "Can't parse phy_sku in B0, empty sections\n");
+ return ENOENT;
+ }
+
+ hw = (const uint16_t *)
+ sections[IWM_NVM_SECTION_TYPE_HW_8000].data;
+ } else {
+ panic("unknown device family %d\n", sc->sc_device_family);
}
- 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;
+ regulatory = (const uint16_t *)
+ sections[IWM_NVM_SECTION_TYPE_REGULATORY].data;
+ mac_override = (const uint16_t *)
+ sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data;
+ phy_sku = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data;
+
+ return iwm_parse_nvm_data(sc, hw, sw, calib, mac_override,
+ phy_sku, regulatory);
}
static int
@@ -1864,38 +2255,34 @@
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 */
- IWM_DPRINTF(sc, IWM_DEBUG_EEPROM,
- "%s: Read NVM\n",
- __func__);
+ memset(nvm_sections, 0 , sizeof(nvm_sections));
- memset(nvm_sections, 0, sizeof(nvm_sections));
+ buf = malloc(bufsz, M_DEVBUF, M_NOWAIT);
+ 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_NOWAIT);
- if (nvm_buffer == NULL)
- return (ENOMEM);
for (i = 0; i < nitems(nvm_to_read); i++) {
section = nvm_to_read[i];
KASSERT(section <= nitems(nvm_sections),
("too many sections"));
- error = iwm_nvm_read_section(sc, section, nvm_buffer, &len);
- if (error)
- break;
-
- temp = malloc(len, M_DEVBUF, M_NOWAIT);
- if (temp == NULL) {
+ error = iwm_nvm_read_section(sc, section, buf, &len, bufsz);
+ if (error) {
+ error = 0;
+ continue;
+ }
+ nvm_sections[section].data = malloc(len, M_DEVBUF, M_NOWAIT);
+ if (nvm_sections[section].data == NULL) {
error = ENOMEM;
break;
}
- 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);
+ free(buf, M_DEVBUF);
if (error == 0)
error = iwm_parse_nvm_sections(sc, nvm_sections);
@@ -1913,21 +2300,52 @@
*/
static 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;
+}
+
+static 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(dma->tag, dma->map, 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),
@@ -1953,14 +2371,133 @@
if ((error = msleep(&sc->sc_fw, &sc->sc_mtx, 0, "iwmfw", hz)) != 0)
break;
+ if (!sc->sc_fw_chunk_done) {
+ device_printf(sc->sc_dev,
+ "fw chunk addr 0x%x len %d failed to load\n",
+ dst_addr, byte_cnt);
+ }
+
+ 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_cpu_sections_8000(struct iwm_softc *sc, struct iwm_fw_sects *fws,
+ int cpu, int *first_ucode_section)
+{
+ int shift_param;
+ int i, error = 0, sec_num = 0x1;
+ uint32_t val, last_read_idx = 0;
+ const void *data;
+ uint32_t dlen;
+ uint32_t offset;
+
+ if (cpu == 1) {
+ shift_param = 0;
+ *first_ucode_section = 0;
+ } else {
+ shift_param = 16;
+ (*first_ucode_section)++;
+ }
+
+ for (i = *first_ucode_section; i < IWM_UCODE_SECT_MAX; i++) {
+ last_read_idx = i;
+ data = fws->fw_sect[i].fws_data;
+ dlen = fws->fw_sect[i].fws_len;
+ offset = fws->fw_sect[i].fws_devoff;
+
+ /*
+ * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between
+ * CPU1 to CPU2.
+ * PAGING_SEPARATOR_SECTION delimiter - separate between
+ * CPU2 non paged to CPU2 paging sec.
+ */
+ if (!data || offset == IWM_CPU1_CPU2_SEPARATOR_SECTION ||
+ offset == IWM_PAGING_SEPARATOR_SECTION)
+ break;
+
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "LOAD FIRMWARE chunk %d offset 0x%x len %d for cpu %d\n",
+ i, offset, dlen, cpu);
+
+ if (dlen > sc->sc_fwdmasegsz) {
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "chunk %d too large (%d bytes)\n", i, dlen);
+ error = EFBIG;
+ } else {
+ error = iwm_firmware_load_sect(sc, offset, data, dlen);
+ }
+ if (error) {
+ device_printf(sc->sc_dev,
+ "could not load firmware chunk %d (error %d)\n",
+ i, error);
+ return error;
+ }
+
+ /* Notify the ucode of the loaded section number and status */
+ if (iwm_nic_lock(sc)) {
+ val = IWM_READ(sc, IWM_FH_UCODE_LOAD_STATUS);
+ val = val | (sec_num << shift_param);
+ IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, val);
+ sec_num = (sec_num << 1) | 0x1;
+ iwm_nic_unlock(sc);
+
+ /*
+ * The firmware won't load correctly without this delay.
+ */
+ DELAY(8000);
+ }
+ }
+
+ *first_ucode_section = last_read_idx;
+
+ if (iwm_nic_lock(sc)) {
+ if (cpu == 1)
+ IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, 0xFFFF);
+ else
+ IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, 0xFFFFFFFF);
+ iwm_nic_unlock(sc);
+ }
+
+ return 0;
+}
+
+int
+iwm_load_firmware_8000(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
+{
+ struct iwm_fw_sects *fws;
+ int error = 0;
+ int first_ucode_section;
+
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET, "loading ucode type %d\n",
+ ucode_type);
+
+ fws = &sc->sc_fw.fw_sects[ucode_type];
+
+ /* configure the ucode to be ready to get the secured image */
+ /* release CPU reset */
+ iwm_write_prph(sc, IWM_RELEASE_CPU_RESET, IWM_RELEASE_CPU_RESET_BIT);
+
+ /* load to FW the binary Secured sections of CPU1 */
+ error = iwm_load_cpu_sections_8000(sc, fws, 1, &first_ucode_section);
+ if (error)
+ return error;
+
+ /* load to FW the binary sections of CPU2 */
+ return iwm_load_cpu_sections_8000(sc, fws, 2, &first_ucode_section);
+}
+
static 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;
const void *data;
uint32_t dlen;
uint32_t offset;
@@ -1975,21 +2512,57 @@
IWM_DPRINTF(sc, IWM_DEBUG_FIRMWARE_TLV,
"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) {
+ IWM_DPRINTF(sc, IWM_DEBUG_FIRMWARE_TLV,
+ "chunk %d too large (%d bytes)\n", i, dlen);
+ error = EFBIG;
+ } else {
+ error = iwm_firmware_load_sect(sc, offset, data, dlen);
+ }
if (error) {
device_printf(sc->sc_dev,
- "%s: chunk %u of %u returned error %02d\n",
- __func__, i, fws->fw_count, error);
+ "could not load firmware chunk %u of %u "
+ "(error=%d)\n", i, fws->fw_count, error);
return error;
}
}
- /* wait for the firmware to load */
IWM_WRITE(sc, IWM_CSR_RESET, 0);
+ return 0;
+}
+
+static int
+iwm_load_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
+{
+ int error, w;
+
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000)
+ error = iwm_load_firmware_8000(sc, ucode_type);
+ else
+ 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 = msleep(&sc->sc_uc, &sc->sc_mtx, 0, "iwmuc", hz/10);
}
+ if (error || !sc->sc_uc.uc_ok) {
+ device_printf(sc->sc_dev, "could not load firmware\n");
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) {
+ device_printf(sc->sc_dev, "cpu1 status: 0x%x\n",
+ iwm_read_prph(sc, IWM_SB_CPU_1_STATUS));
+ device_printf(sc->sc_dev, "cpu2 status: 0x%x\n",
+ iwm_read_prph(sc, IWM_SB_CPU_2_STATUS));
+ }
+ }
+
+ /*
+ * Give the firmware some time to initialize.
+ * Accessing it too early causes errors.
+ */
+ msleep(&w, &sc->sc_mtx, 0, "iwmfwinit", hz);
return error;
}
@@ -2063,17 +2636,25 @@
enum iwm_ucode_type old_type = sc->sc_uc_current;
int error;
- if ((error = iwm_read_firmware(sc, ucode_type)) != 0)
+ if ((error = iwm_read_firmware(sc, ucode_type)) != 0) {
+ device_printf(sc->sc_dev, "iwm_read_firmware: failed %d\n",
+ error);
return error;
+ }
sc->sc_uc_current = ucode_type;
error = iwm_start_fw(sc, ucode_type);
if (error) {
+ device_printf(sc->sc_dev, "iwm_start_fw: failed %d\n", error);
sc->sc_uc_current = old_type;
return error;
}
- return iwm_post_alive(sc);
+ error = iwm_post_alive(sc);
+ if (error) {
+ device_printf(sc->sc_dev, "iwm_fw_alive: failed %d\n", error);
+ }
+ return error;
}
/*
@@ -2109,26 +2690,31 @@
}
IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, 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_NOWAIT);
- if (sc->sc_scan_cmd == NULL)
- return (ENOMEM);
-
return 0;
}
+ if ((error = iwm_send_bt_init_conf(sc)) != 0) {
+ device_printf(sc->sc_dev,
+ "failed to send bt coex configuration: %d\n", 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) {
+ device_printf(sc->sc_dev,
+ "failed to send antennas before calibration: %d\n", 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 ) {
device_printf(sc->sc_dev,
"%s: failed to run internal calibration: %d\n",
@@ -2140,10 +2726,18 @@
* Nothing to do but wait for the init complete notification
* from the firmware
*/
- while (!sc->sc_init_complete)
- if ((error = msleep(&sc->sc_init_complete, &sc->sc_mtx,
- 0, "iwminit", 2*hz)) != 0)
+ while (!sc->sc_init_complete) {
+ error = msleep(&sc->sc_init_complete, &sc->sc_mtx,
+ 0, "iwminit", 2*hz);
+ if (error) {
+ device_printf(sc->sc_dev, "init complete failed: %d\n",
+ sc->sc_init_complete);
break;
+ }
+ }
+
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET, "init %scomplete\n",
+ sc->sc_init_complete ? "" : "not ");
return error;
}
@@ -2160,18 +2754,17 @@
struct iwm_rx_data *data = &ring->data[idx];
struct mbuf *m;
bus_dmamap_t dmamap = NULL;
- int error;
- bus_addr_t paddr;
+ bus_dma_segment_t seg;
+ int nsegs, error;
m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWM_RBUF_SIZE);
if (m == NULL)
return ENOBUFS;
m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
- error = bus_dmamap_load(ring->data_dmat, ring->spare_map,
- mtod(m, void *), IWM_RBUF_SIZE, iwm_dma_map_addr,
- &paddr, BUS_DMA_NOWAIT);
- if (error != 0 && error != EFBIG) {
+ error = bus_dmamap_load_mbuf_sg(ring->data_dmat, ring->spare_map, m,
+ &seg, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
device_printf(sc->sc_dev,
"%s: can't map mbuf, error %d\n", __func__, error);
goto fail;
@@ -2189,13 +2782,14 @@
data->m = m;
/* Update RX descriptor. */
- ring->desc[idx] = htole32(paddr >> 8);
+ KASSERT((seg.ds_addr & 255) == 0, ("seg.ds_addr not aligned"));
+ ring->desc[idx] = htole32(seg.ds_addr >> 8);
bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map,
BUS_DMASYNC_PREWRITE);
return 0;
fail:
- m_free(m);
+ m_freem(m);
return error;
}
@@ -2839,11 +3433,11 @@
KASSERT(data->in != NULL, ("node is NULL"));
IWM_DPRINTF(sc, IWM_DEBUG_XMIT,
- "sending data: qid=%d idx=%d len=%d nsegs=%d txflags=0x%08x rate_n_flags=0x%08x rateidx=%d\n",
+ "sending data: qid=%d idx=%d len=%d nsegs=%d txflags=0x%08x rate_n_flags=0x%08x rateidx=%u\n",
ring->qid, ring->cur, totlen, nsegs,
le32toh(tx->tx_flags),
le32toh(tx->rate_n_flags),
- (int) tx->initial_rate_index
+ tx->initial_rate_index
);
/* Fill TX descriptor. */
@@ -2956,52 +3550,19 @@
* BEGIN mvm/sta.c
*/
-static 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;
- IEEE80211_ADDR_COPY(cmd_v5->addr, cmd_v6->addr);
- 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;
-}
-
static 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 */
static 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;
@@ -3012,12 +3573,19 @@
= htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID,
IWM_DEFAULT_COLOR));
if (!update) {
- add_sta_cmd.tfd_queue_msk = htole32(0xf);
+ int ac;
+ for (ac = 0; ac < WME_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);
status = IWM_ADD_STA_SUCCESS;
ret = iwm_mvm_send_add_sta_cmd_status(sc, &add_sta_cmd, &status);
@@ -3052,7 +3620,7 @@
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;
@@ -3061,6 +3629,7 @@
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)
IEEE80211_ADDR_COPY(cmd.addr, addr);
@@ -3089,8 +3658,12 @@
{
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);
@@ -3210,6 +3783,10 @@
in->in_assoc = 0;
+ error = iwm_mvm_sf_config(sc, IWM_SF_FULL_ON);
+ if (error != 0)
+ return error;
+
error = iwm_allow_mcast(vap, sc);
if (error) {
device_printf(sc->sc_dev,
@@ -3222,7 +3799,7 @@
*
* Linux iwlwifi doesn't reset the nic each time, nor does it
* call ctxt_add() here. Instead, it adds it during vap creation,
- * and always does does a mac_ctx_changed().
+ * and always does a mac_ctx_changed().
*
* The openbsd port doesn't attempt to do that - it reset things
* at odd states and does the add here.
@@ -3342,7 +3919,7 @@
* 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)
@@ -3448,6 +4025,10 @@
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;
+
/*
* are these used? (we don't do SISO or MIMO)
* need to set them to non-zero, though, or we get an error.
@@ -3471,7 +4052,7 @@
int nextant;
if (txant == 0)
- txant = IWM_FW_VALID_TX_ANT(sc);
+ txant = iwm_fw_valid_tx_ant(sc);
nextant = 1<<(ffs(txant)-1);
txant &= ~nextant;
@@ -3567,7 +4148,12 @@
"Force transition to INIT; MGT=%d\n", arg);
IWM_UNLOCK(sc);
IEEE80211_LOCK(ic);
- vap->iv_newstate(vap, IEEE80211_S_INIT, arg);
+ /* Always pass arg as -1 since we can't Tx right now. */
+ /*
+ * XXX arg is just ignored anyway when transitioning
+ * to IEEE80211_S_INIT.
+ */
+ vap->iv_newstate(vap, IEEE80211_S_INIT, -1);
IWM_DPRINTF(sc, IWM_DEBUG_STATE,
"Going INIT->SCAN\n");
nstate = IEEE80211_S_SCAN;
@@ -3578,7 +4164,6 @@
switch (nstate) {
case IEEE80211_S_INIT:
- sc->sc_scanband = 0;
break;
case IEEE80211_S_AUTH:
@@ -3630,6 +4215,7 @@
"%s: IWM_LQ_CMD failed\n", __func__);
}
+ iwm_mvm_led_enable(sc);
break;
}
@@ -3647,46 +4233,258 @@
{
struct iwm_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
- int done;
- int error;
IWM_DPRINTF(sc, IWM_DEBUG_SCAN | IWM_DEBUG_TRACE,
"%s: scan ended\n",
__func__);
- IWM_LOCK(sc);
- if (sc->sc_scanband == IEEE80211_CHAN_2GHZ &&
- sc->sc_nvm.sku_cap_band_52GHz_enable) {
- done = 0;
- if ((error = iwm_mvm_scan_request(sc,
- IEEE80211_CHAN_5GHZ, 0, NULL, 0)) != 0) {
- device_printf(sc->sc_dev,
- "could not initiate 5 GHz scan\n");
- done = 1;
+ ieee80211_scan_done(TAILQ_FIRST(&ic->ic_vaps));
+}
+
+/*
+ * 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)
+ },
+};
+
+static void
+iwm_mvm_fill_sf_command(struct iwm_softc *sc, struct iwm_sf_cfg_cmd *sf_cmd,
+ struct ieee80211_node *ni)
+{
+ int i, j, watermark;
+
+ sf_cmd->watermark[IWM_SF_LONG_DELAY_ON] = htole32(IWM_SF_W_MARK_SCAN);
+
+ /*
+ * If we are in association flow - check antenna configuration
+ * capabilities of the AP station, and choose the watermark accordingly.
+ */
+ if (ni) {
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+#ifdef notyet
+ if (ni->ni_rxmcs[2] != 0)
+ watermark = IWM_SF_W_MARK_MIMO3;
+ else if (ni->ni_rxmcs[1] != 0)
+ watermark = IWM_SF_W_MARK_MIMO2;
+ else
+#endif
+ watermark = IWM_SF_W_MARK_SISO;
+ } else {
+ watermark = IWM_SF_W_MARK_LEGACY;
}
+ /* default watermark value for unassociated mode. */
} else {
- done = 1;
+ watermark = IWM_SF_W_MARK_MIMO2;
}
+ sf_cmd->watermark[IWM_SF_FULL_ON] = htole32(watermark);
- if (done) {
- IWM_UNLOCK(sc);
- ieee80211_scan_done(TAILQ_FIRST(&ic->ic_vaps));
- IWM_LOCK(sc);
- sc->sc_scanband = 0;
+ for (i = 0; i < IWM_SF_NUM_SCENARIO; i++) {
+ for (j = 0; j < IWM_SF_NUM_TIMEOUT_TYPES; j++) {
+ sf_cmd->long_delay_timeouts[i][j] =
+ htole32(IWM_SF_LONG_DELAY_AGING_TIMER);
+ }
+ }
+
+ if (ni) {
+ memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout,
+ sizeof(iwm_sf_full_timeout));
+ } else {
+ memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout_def,
+ sizeof(iwm_sf_full_timeout_def));
+ }
+}
+
+static int
+iwm_mvm_sf_config(struct iwm_softc *sc, enum iwm_sf_state new_state)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ struct iwm_sf_cfg_cmd sf_cmd = {
+ .state = htole32(IWM_SF_FULL_ON),
+ };
+ int ret = 0;
+
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000)
+ sf_cmd.state |= htole32(IWM_SF_CFG_DUMMY_NOTIF_OFF);
+
+ 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, vap->iv_bss);
+ break;
+ default:
+ IWM_DPRINTF(sc, IWM_DEBUG_PWRSAVE,
+ "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;
+}
+
+static 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);
+}
+
+static 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);
+
+ IWM_DPRINTF(sc, IWM_DEBUG_NODE,
+ "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 */
+
+ IWM_DPRINTF(sc, IWM_DEBUG_NODE,
+ "regulatory domain '%c%c' (%d channels available)\n",
+ mcc >> 8, mcc & 0xff, n_channels);
+#endif
+ iwm_free_resp(sc, &hcmd);
+
+ return 0;
+}
+
+static 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) {
+ device_printf(sc->sc_dev,
+ "failed to change thermal tx backoff\n");
}
- IWM_UNLOCK(sc);
}
static int
iwm_init_hw(struct iwm_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- int error, i, qid;
+ int error, i, ac;
- if ((error = iwm_start_hw(sc)) != 0)
+ if ((error = iwm_start_hw(sc)) != 0) {
+ printf("iwm_start_hw: failed %d\n", error);
return error;
+ }
if ((error = iwm_run_init_mvm_ucode(sc, 0)) != 0) {
+ printf("iwm_run_init_mvm_ucode: failed %d\n", error);
return error;
}
@@ -3707,19 +4505,32 @@
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) {
+ device_printf(sc->sc_dev, "bt init conf failed\n");
+ goto error;
+ }
+
+ if ((error = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc))) != 0) {
+ device_printf(sc->sc_dev, "antenna config failed\n");
goto error;
+ }
/* Send phy db control command and then phy db calibration*/
- if ((error = iwm_send_phy_db_data(sc)) != 0)
+ if ((error = iwm_send_phy_db_data(sc)) != 0) {
+ device_printf(sc->sc_dev, "phy_db_data failed\n");
goto error;
+ }
- if ((error = iwm_send_phy_cfg_cmd(sc)) != 0)
+ if ((error = iwm_send_phy_cfg_cmd(sc)) != 0) {
+ device_printf(sc->sc_dev, "phy_cfg_cmd failed\n");
goto error;
+ }
/* Add auxiliary station for scanning */
- if ((error = iwm_mvm_add_aux_sta(sc)) != 0)
+ if ((error = iwm_mvm_add_aux_sta(sc)) != 0) {
+ device_printf(sc->sc_dev, "add_aux_sta failed\n");
goto error;
+ }
for (i = 0; i < IWM_NUM_PHY_CTX; i++) {
/*
@@ -3732,13 +4543,35 @@
goto error;
}
+ /* Initialize tx backoffs to the minimum. */
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000)
+ 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;
+ }
+
+ if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
+ if ((error = iwm_mvm_config_umac_scan(sc)) != 0)
+ goto error;
+ }
+
+ /* Enable Tx queues. */
+ for (ac = 0; ac < WME_NUM_AC; ac++) {
+ error = iwm_enable_txq(sc, IWM_STATION_ID, ac,
+ iwm_mvm_ac_to_tx_fifo[ac]);
+ if (error)
+ goto error;
+ }
+
+ if ((error = iwm_mvm_disable_beacon_filter(sc)) != 0) {
+ device_printf(sc->sc_dev, "failed to disable beacon filter\n");
+ goto error;
}
return 0;
@@ -3774,6 +4607,10 @@
return (error);
}
+/*
+ * ifnet interfaces
+ */
+
static void
iwm_init(struct iwm_softc *sc)
{
@@ -3786,12 +4623,13 @@
sc->sc_flags &= ~IWM_FLAG_STOPPED;
if ((error = iwm_init_hw(sc)) != 0) {
+ printf("iwm_init_hw failed %d\n", error);
iwm_stop(sc);
return;
}
/*
- * Ok, firmware loaded and we are jogging
+ * Ok, firmware loaded and we are jogging
*/
sc->sc_flags |= IWM_FLAG_HW_INITED;
callout_reset(&sc->sc_watchdog_to, hz, iwm_watchdog, sc);
@@ -3852,7 +4690,6 @@
sc->sc_flags &= ~IWM_FLAG_HW_INITED;
sc->sc_flags |= IWM_FLAG_STOPPED;
sc->sc_generation++;
- sc->sc_scanband = 0;
iwm_led_blink_stop(sc);
sc->sc_tx_timer = 0;
iwm_stop_device(sc);
@@ -3871,7 +4708,7 @@
iwm_nic_error(sc);
#endif
ieee80211_restart_all(ic);
- counter_u64_add(ic->ic_oerrors, 1);
+ counter_u64_add(sc->sc_ic.ic_oerrors, 1);
return;
}
}
@@ -3914,8 +4751,8 @@
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 */
@@ -3927,8 +4764,9 @@
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 */
@@ -3945,7 +4783,7 @@
* 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 */
@@ -3956,6 +4794,31 @@
uint32_t u_timestamp; /* indicate when the date and time of the
* compilation */
uint32_t flow_handler; /* FH read/write pointers, RX credit */
+} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;
+
+/*
+ * UMAC error struct - relevant starting from family 8000 chip.
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwm_umac_error_event_table {
+ uint32_t valid; /* (nonzero) valid, (0) log is empty */
+ uint32_t error_id; /* type of error */
+ uint32_t blink1; /* branch link */
+ uint32_t blink2; /* branch link */
+ uint32_t ilink1; /* interrupt link */
+ uint32_t ilink2; /* interrupt link */
+ uint32_t data1; /* error-specific data */
+ uint32_t data2; /* error-specific data */
+ uint32_t data3; /* error-specific data */
+ uint32_t umac_major;
+ uint32_t umac_minor;
+ uint32_t frame_pointer; /* core register 27*/
+ uint32_t stack_pointer; /* core register 28 */
+ uint32_t cmd_header; /* latest host cmd sent to UMAC */
+ uint32_t nic_isr_pref; /* ISR status register */
} __packed;
#define ERROR_START_OFFSET (1 * sizeof(uint32_t))
@@ -3997,6 +4860,53 @@
return advanced_lookup[i].name;
}
+static void
+iwm_nic_umac_error(struct iwm_softc *sc)
+{
+ struct iwm_umac_error_event_table table;
+ uint32_t base;
+
+ base = sc->sc_uc.uc_umac_error_event_table;
+
+ if (base < 0x800000) {
+ device_printf(sc->sc_dev, "Invalid error log pointer 0x%08x\n",
+ base);
+ return;
+ }
+
+ if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) {
+ device_printf(sc->sc_dev, "reading errlog failed\n");
+ return;
+ }
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ device_printf(sc->sc_dev, "Start UMAC Error Log Dump:\n");
+ device_printf(sc->sc_dev, "Status: 0x%x, count: %d\n",
+ sc->sc_flags, table.valid);
+ }
+
+ device_printf(sc->sc_dev, "0x%08X | %s\n", table.error_id,
+ iwm_desc_lookup(table.error_id));
+ device_printf(sc->sc_dev, "0x%08X | umac branchlink1\n", table.blink1);
+ device_printf(sc->sc_dev, "0x%08X | umac branchlink2\n", table.blink2);
+ device_printf(sc->sc_dev, "0x%08X | umac interruptlink1\n",
+ table.ilink1);
+ device_printf(sc->sc_dev, "0x%08X | umac interruptlink2\n",
+ table.ilink2);
+ device_printf(sc->sc_dev, "0x%08X | umac data1\n", table.data1);
+ device_printf(sc->sc_dev, "0x%08X | umac data2\n", table.data2);
+ device_printf(sc->sc_dev, "0x%08X | umac data3\n", table.data3);
+ device_printf(sc->sc_dev, "0x%08X | umac major\n", table.umac_major);
+ device_printf(sc->sc_dev, "0x%08X | umac minor\n", table.umac_minor);
+ device_printf(sc->sc_dev, "0x%08X | frame pointer\n",
+ table.frame_pointer);
+ device_printf(sc->sc_dev, "0x%08X | stack pointer\n",
+ table.stack_pointer);
+ device_printf(sc->sc_dev, "0x%08X | last host cmd\n", table.cmd_header);
+ device_printf(sc->sc_dev, "0x%08X | isr status reg\n",
+ table.nic_isr_pref);
+}
+
/*
* Support for dumping the error log seemed like a good idea ...
* but it's mostly hex junk and the only sensible thing is the
@@ -4012,13 +4922,13 @@
device_printf(sc->sc_dev, "dumping device error log\n");
base = sc->sc_uc.uc_error_event_table;
- if (base < 0x800000 || base >= 0x80C000) {
+ if (base < 0x800000) {
device_printf(sc->sc_dev,
- "Not valid error log pointer 0x%08x\n", base);
+ "Invalid error log pointer 0x%08x\n", 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))) {
device_printf(sc->sc_dev, "reading errlog failed\n");
return;
}
@@ -4029,15 +4939,17 @@
}
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
- device_printf(sc->sc_dev, "Start IWL Error Log Dump:\n");
+ device_printf(sc->sc_dev, "Start Error Log Dump:\n");
device_printf(sc->sc_dev, "Status: 0x%x, count: %d\n",
sc->sc_flags, table.valid);
}
device_printf(sc->sc_dev, "0x%08X | %-28s\n", table.error_id,
- iwm_desc_lookup(table.error_id));
- device_printf(sc->sc_dev, "%08X | uPc\n", table.pc);
- device_printf(sc->sc_dev, "%08X | branchlink1\n", table.blink1);
+ iwm_desc_lookup(table.error_id));
+ device_printf(sc->sc_dev, "%08X | trm_hw_status0\n",
+ table.trm_hw_status0);
+ device_printf(sc->sc_dev, "%08X | trm_hw_status1\n",
+ table.trm_hw_status1);
device_printf(sc->sc_dev, "%08X | branchlink2\n", table.blink2);
device_printf(sc->sc_dev, "%08X | interruptlink1\n", table.ilink1);
device_printf(sc->sc_dev, "%08X | interruptlink2\n", table.ilink2);
@@ -4049,8 +4961,10 @@
device_printf(sc->sc_dev, "%08X | tsf hi\n", table.tsf_hi);
device_printf(sc->sc_dev, "%08X | time gp1\n", table.gp1);
device_printf(sc->sc_dev, "%08X | time gp2\n", table.gp2);
- device_printf(sc->sc_dev, "%08X | time gp3\n", table.gp3);
- device_printf(sc->sc_dev, "%08X | uCode version\n", table.ucode_ver);
+ device_printf(sc->sc_dev, "%08X | uCode revision type\n",
+ table.fw_rev_type);
+ device_printf(sc->sc_dev, "%08X | uCode version major\n", table.major);
+ device_printf(sc->sc_dev, "%08X | uCode version minor\n", table.minor);
device_printf(sc->sc_dev, "%08X | hw version\n", table.hw_ver);
device_printf(sc->sc_dev, "%08X | board version\n", table.brd_ver);
device_printf(sc->sc_dev, "%08X | hcmd\n", table.hcmd);
@@ -4059,7 +4973,7 @@
device_printf(sc->sc_dev, "%08X | isr2\n", table.isr2);
device_printf(sc->sc_dev, "%08X | isr3\n", table.isr3);
device_printf(sc->sc_dev, "%08X | isr4\n", table.isr4);
- device_printf(sc->sc_dev, "%08X | isr_pref\n", table.isr_pref);
+ device_printf(sc->sc_dev, "%08X | last cmd Id\n", table.last_cmd_id);
device_printf(sc->sc_dev, "%08X | wait_event\n", table.wait_event);
device_printf(sc->sc_dev, "%08X | l2p_control\n", table.l2p_control);
device_printf(sc->sc_dev, "%08X | l2p_duration\n", table.l2p_duration);
@@ -4068,6 +4982,9 @@
device_printf(sc->sc_dev, "%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
device_printf(sc->sc_dev, "%08X | timestamp\n", table.u_timestamp);
device_printf(sc->sc_dev, "%08X | flow_handler\n", table.flow_handler);
+
+ if (sc->sc_uc.uc_umac_error_event_table)
+ iwm_nic_umac_error(sc);
}
#endif
@@ -4099,12 +5016,16 @@
BUS_DMASYNC_POSTREAD);
hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff;
+
+ /*
+ * Process responses
+ */
while (sc->rxq.cur != hw) {
struct iwm_rx_ring *ring = &sc->rxq;
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->rxq.data_dmat, data->map,
BUS_DMASYNC_POSTREAD);
@@ -4113,10 +5034,10 @@
qid = pkt->hdr.qid & ~0x80;
idx = pkt->hdr.idx;
+ code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code);
IWM_DPRINTF(sc, IWM_DEBUG_INTR,
- "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);
+ "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.
@@ -4128,7 +5049,7 @@
continue;
}
- switch (pkt->hdr.code) {
+ switch (code) {
case IWM_REPLY_RX_PHY_CMD:
iwm_mvm_rx_rx_phy_cmd(sc, pkt, data);
break;
@@ -4179,16 +5100,56 @@
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;
+ }
- 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(*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);
+ sc->sc_uc.uc_umac_error_event_table
+ = le32toh(resp2->error_info_addr);
+ if (resp2->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(*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);
+ sc->sc_uc.uc_umac_error_event_table
+ = le32toh(resp3->error_info_addr);
+ 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);
@@ -4210,6 +5171,7 @@
break; }
case IWM_NVM_ACCESS_CMD:
+ case IWM_MCC_UPDATE_CMD:
if (sc->sc_wantresp == ((qid << 16) | idx)) {
bus_dmamap_sync(sc->rxq.data_dmat, data->map,
BUS_DMASYNC_POSTREAD);
@@ -4218,6 +5180,21 @@
}
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';
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "fw source %d sent CC '%s'\n",
+ notif->source_id, sc->sc_fw_mcc);
+ break; }
+
+ case IWM_DTS_MEASUREMENT_NOTIFICATION:
+ break;
+
case IWM_PHY_CONFIGURATION_CMD:
case IWM_TX_ANT_CONFIGURATION_CMD:
case IWM_ADD_STA:
@@ -4228,12 +5205,17 @@
case IWM_BINDING_CONTEXT_CMD:
case IWM_TIME_EVENT_CMD:
case IWM_SCAN_REQUEST_CMD:
+ case IWM_WIDE_ID(IWM_ALWAYS_LONG_GROUP, IWM_SCAN_CFG_CMD):
+ case IWM_WIDE_ID(IWM_ALWAYS_LONG_GROUP, IWM_SCAN_REQ_UMAC):
+ 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,
@@ -4250,11 +5232,42 @@
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);
+ ieee80211_runtask(&sc->sc_ic, &sc->sc_es_task);
+ break;
+ }
+
+ case IWM_SCAN_COMPLETE_UMAC: {
+ struct iwm_umac_scan_complete *notif;
+ SYNC_RESP_STRUCT(notif, pkt);
+
+ IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
+ "UMAC scan complete, status=0x%x\n",
+ notif->status);
+#if 0 /* XXX This would be a duplicate scan end call */
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_es_task);
+#endif
+ break;
+ }
+
+ case IWM_SCAN_ITERATION_COMPLETE_UMAC: {
+ struct iwm_umac_scan_iter_complete_notif *notif;
SYNC_RESP_STRUCT(notif, pkt);
- ieee80211_runtask(ic, &sc->sc_es_task);
- break; }
+
+ IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan iteration "
+ "complete, status=0x%x, %d channels scanned\n",
+ notif->status, notif->scanned_channels);
+ ieee80211_runtask(&sc->sc_ic, &sc->sc_es_task);
+ break;
+ }
case IWM_REPLY_ERROR: {
struct iwm_error_resp *resp;
@@ -4264,7 +5277,8 @@
"firmware error 0x%x, cmd 0x%x\n",
le32toh(resp->error_type),
resp->cmd_id);
- break; }
+ break;
+ }
case IWM_TIME_EVENT_NOTIFICATION: {
struct iwm_time_event_notif *notif;
@@ -4272,12 +5286,25 @@
IWM_DPRINTF(sc, IWM_DEBUG_INTR,
"TE notif status = 0x%x action = 0x%x\n",
- notif->status, notif->action);
- break; }
+ notif->status, notif->action);
+ break;
+ }
case IWM_MCAST_FILTER_CMD:
break;
+ case IWM_SCD_QUEUE_CFG: {
+ struct iwm_scd_txq_cfg_rsp *rsp;
+ SYNC_RESP_STRUCT(rsp, pkt);
+
+ IWM_DPRINTF(sc, IWM_DEBUG_CMD,
+ "queue cfg token=0x%x sta_id=%d "
+ "tid=%d scd_queue=%d\n",
+ rsp->token, rsp->sta_id, rsp->tid,
+ rsp->scd_queue);
+ break;
+ }
+
default:
device_printf(sc->sc_dev,
"frame %d/%d %x UNHANDLED (this should "
@@ -4480,10 +5507,14 @@
#define PCI_VENDOR_INTEL 0x8086
#define PCI_PRODUCT_INTEL_WL_3160_1 0x08b3
#define PCI_PRODUCT_INTEL_WL_3160_2 0x08b4
+#define PCI_PRODUCT_INTEL_WL_3165_1 0x3165
+#define PCI_PRODUCT_INTEL_WL_3165_2 0x3166
#define PCI_PRODUCT_INTEL_WL_7260_1 0x08b1
#define PCI_PRODUCT_INTEL_WL_7260_2 0x08b2
#define PCI_PRODUCT_INTEL_WL_7265_1 0x095a
#define PCI_PRODUCT_INTEL_WL_7265_2 0x095b
+#define PCI_PRODUCT_INTEL_WL_8260_1 0x24f3
+#define PCI_PRODUCT_INTEL_WL_8260_2 0x24f4
static const struct iwm_devices {
uint16_t device;
@@ -4491,10 +5522,14 @@
} iwm_devices[] = {
{ PCI_PRODUCT_INTEL_WL_3160_1, "Intel Dual Band Wireless AC 3160" },
{ PCI_PRODUCT_INTEL_WL_3160_2, "Intel Dual Band Wireless AC 3160" },
+ { PCI_PRODUCT_INTEL_WL_3165_1, "Intel Dual Band Wireless AC 3165" },
+ { PCI_PRODUCT_INTEL_WL_3165_2, "Intel Dual Band Wireless AC 3165" },
{ PCI_PRODUCT_INTEL_WL_7260_1, "Intel Dual Band Wireless AC 7260" },
{ PCI_PRODUCT_INTEL_WL_7260_2, "Intel Dual Band Wireless AC 7260" },
{ PCI_PRODUCT_INTEL_WL_7265_1, "Intel Dual Band Wireless AC 7265" },
{ PCI_PRODUCT_INTEL_WL_7265_2, "Intel Dual Band Wireless AC 7265" },
+ { PCI_PRODUCT_INTEL_WL_8260_1, "Intel Dual Band Wireless AC 8260" },
+ { PCI_PRODUCT_INTEL_WL_8260_2, "Intel Dual Band Wireless AC 8260" },
};
static int
@@ -4502,12 +5537,13 @@
{
int i;
- for (i = 0; i < nitems(iwm_devices); i++)
+ for (i = 0; i < nitems(iwm_devices); i++) {
if (pci_get_vendor(dev) == PCI_VENDOR_INTEL &&
pci_get_device(dev) == iwm_devices[i].device) {
device_set_desc(dev, iwm_devices[i].name);
return (BUS_PROBE_DEFAULT);
}
+ }
return (ENXIO);
}
@@ -4519,21 +5555,42 @@
sc = device_get_softc(dev);
+ sc->sc_hw_rev = IWM_READ(sc, IWM_CSR_HW_REV);
switch (pci_get_device(dev)) {
case PCI_PRODUCT_INTEL_WL_3160_1:
case PCI_PRODUCT_INTEL_WL_3160_2:
sc->sc_fwname = "iwm3160fw";
sc->host_interrupt_operation_mode = 1;
+ sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
+ sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
+ return (0);
+ case PCI_PRODUCT_INTEL_WL_3165_1:
+ case PCI_PRODUCT_INTEL_WL_3165_2:
+ sc->sc_fwname = "iwm7265fw";
+ sc->host_interrupt_operation_mode = 0;
+ sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
+ sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
return (0);
case PCI_PRODUCT_INTEL_WL_7260_1:
case PCI_PRODUCT_INTEL_WL_7260_2:
sc->sc_fwname = "iwm7260fw";
sc->host_interrupt_operation_mode = 1;
+ sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
+ sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
return (0);
case PCI_PRODUCT_INTEL_WL_7265_1:
case PCI_PRODUCT_INTEL_WL_7265_2:
sc->sc_fwname = "iwm7265fw";
sc->host_interrupt_operation_mode = 0;
+ sc->sc_device_family = IWM_DEVICE_FAMILY_7000;
+ sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
+ return (0);
+ case PCI_PRODUCT_INTEL_WL_8260_1:
+ case PCI_PRODUCT_INTEL_WL_8260_2:
+ sc->sc_fwname = "iwm8000Cfw";
+ sc->host_interrupt_operation_mode = 0;
+ sc->sc_device_family = IWM_DEVICE_FAMILY_8000;
+ sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000;
return (0);
default:
device_printf(dev, "unknown adapter type\n");
@@ -4640,17 +5697,62 @@
if (error != 0)
goto fail;
- sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
-
/*
* We now start fiddling with the hardware
*/
- sc->sc_hw_rev = IWM_READ(sc, IWM_CSR_HW_REV);
+ /*
+ * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have
+ * changed, and now the revision step also includes bit 0-1 (no more
+ * "dash" value). To keep hw_rev backwards compatible - we'll store it
+ * in the old format.
+ */
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000)
+ sc->sc_hw_rev = (sc->sc_hw_rev & 0xfff0) |
+ (IWM_CSR_HW_REV_STEP(sc->sc_hw_rev << 2) << 2);
+
if (iwm_prepare_card_hw(sc) != 0) {
device_printf(dev, "could not initialize hardware\n");
goto fail;
}
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) {
+ int ret;
+ uint32_t hw_step;
+
+ /*
+ * In order to recognize C step the driver should read the
+ * chip version id located at the AUX bus MISC address.
+ */
+ IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
+ IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ DELAY(2);
+
+ ret = iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
+ IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ 25000);
+ if (ret < 0) {
+ device_printf(sc->sc_dev,
+ "Failed to wake up the nic\n");
+ goto fail;
+ }
+
+ if (iwm_nic_lock(sc)) {
+ hw_step = iwm_read_prph(sc, IWM_WFPM_CTRL_REG);
+ hw_step |= IWM_ENABLE_WFPM;
+ iwm_write_prph(sc, IWM_WFPM_CTRL_REG, hw_step);
+ hw_step = iwm_read_prph(sc, IWM_AUX_MISC_REG);
+ hw_step = (hw_step >> IWM_HW_STEP_LOCATION_BITS) & 0xF;
+ if (hw_step == 0x3)
+ sc->sc_hw_rev = (sc->sc_hw_rev & 0xFFFFFFF3) |
+ (IWM_SILICON_C_STEP << 2);
+ iwm_nic_unlock(sc);
+ } else {
+ device_printf(sc->sc_dev, "Failed to lock the nic\n");
+ goto fail;
+ }
+ }
+
/* Allocate DMA memory for firmware transfers. */
if ((error = iwm_alloc_fwmem(sc)) != 0) {
device_printf(dev, "could not allocate memory for firmware\n");
@@ -4744,6 +5846,17 @@
}
static int
+iwm_is_valid_ether_addr(uint8_t *addr)
+{
+ char zero_addr[IEEE80211_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };
+
+ if ((addr[0] & 1) || IEEE80211_ADDR_EQ(zero_addr, addr))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+static int
iwm_update_edca(struct ieee80211com *ic)
{
struct iwm_softc *sc = ic->ic_softc;
@@ -4777,11 +5890,9 @@
goto fail;
}
device_printf(dev,
- "revision: 0x%x, firmware %d.%d (API ver. %d)\n",
+ "hw rev 0x%x, fw ver %s, address %s\n",
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));
+ sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr));
/* not all hardware can do 5GHz band */
if (!sc->sc_nvm.sku_cap_band_52GHz_enable)
@@ -4886,18 +5997,18 @@
iwm_scan_start(struct ieee80211com *ic)
{
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
- struct iwm_softc *sc = ic->ic_softc;
+ struct iwm_softc *sc = ic->ic_softc;
int error;
- if (sc->sc_scanband)
- return;
IWM_LOCK(sc);
- error = iwm_mvm_scan_request(sc, IEEE80211_CHAN_2GHZ, 0, NULL, 0);
- if (error) {
+ if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
+ error = iwm_mvm_umac_scan(sc);
+ else
+ error = iwm_mvm_lmac_scan(sc);
+ if (error != 0) {
device_printf(sc->sc_dev, "could not initiate 2 GHz scan\n");
IWM_UNLOCK(sc);
ieee80211_cancel_scan(vap);
- sc->sc_scanband = 0;
} else {
iwm_led_blink_start(sc);
IWM_UNLOCK(sc);
@@ -4968,8 +6079,8 @@
iwm_init_task(device_get_softc(dev));
IWM_LOCK(sc);
- if (sc->sc_flags & IWM_FLAG_DORESUME) {
- sc->sc_flags &= ~IWM_FLAG_DORESUME;
+ if (sc->sc_flags & IWM_FLAG_SCANNING) {
+ sc->sc_flags &= ~IWM_FLAG_SCANNING;
do_reinit = 1;
}
IWM_UNLOCK(sc);
@@ -4993,7 +6104,7 @@
if (do_stop) {
IWM_LOCK(sc);
iwm_stop(sc);
- sc->sc_flags |= IWM_FLAG_DORESUME;
+ sc->sc_flags |= IWM_FLAG_SCANNING;
IWM_UNLOCK(sc);
}
@@ -5012,8 +6123,9 @@
callout_drain(&sc->sc_led_blink_to);
callout_drain(&sc->sc_watchdog_to);
iwm_stop_device(sc);
- if (do_net80211)
+ if (do_net80211) {
ieee80211_ifdetach(&sc->sc_ic);
+ }
iwm_phy_db_free(sc);
Index: head/sys/dev/iwm/if_iwm_led.h
===================================================================
--- head/sys/dev/iwm/if_iwm_led.h
+++ head/sys/dev/iwm/if_iwm_led.h
@@ -91,11 +91,9 @@
#ifndef __IF_IWM_LED_H__
#define __IF_IWM_LED_H__
-void iwm_mvm_led_enable(struct iwm_softc *);
-void iwm_mvm_led_disable(struct iwm_softc *);
-int iwm_mvm_led_is_enabled(struct iwm_softc *);
-void iwm_led_blink_timeout(void *);
-void iwm_led_blink_start(struct iwm_softc *);
-void iwm_led_blink_stop(struct iwm_softc *);
+extern void iwm_mvm_led_enable(struct iwm_softc *);
+extern void iwm_mvm_led_disable(struct iwm_softc *);
+extern void iwm_led_blink_start(struct iwm_softc *);
+extern void iwm_led_blink_stop(struct iwm_softc *);
#endif /* __IF_IWM_LED_H__ */
Index: head/sys/dev/iwm/if_iwm_led.c
===================================================================
--- head/sys/dev/iwm/if_iwm_led.c
+++ head/sys/dev/iwm/if_iwm_led.c
@@ -148,13 +148,13 @@
IWM_WRITE(sc, IWM_CSR_LED_REG, IWM_CSR_LED_REG_TURN_OFF);
}
-int
+static int
iwm_mvm_led_is_enabled(struct iwm_softc *sc)
{
return (IWM_READ(sc, IWM_CSR_LED_REG) == IWM_CSR_LED_REG_TURN_ON);
}
-void
+static void
iwm_led_blink_timeout(void *arg)
{
struct iwm_softc *sc = arg;
@@ -177,6 +177,6 @@
void
iwm_led_blink_stop(struct iwm_softc *sc)
{
- callout_drain(&sc->sc_led_blink_to);
+ callout_stop(&sc->sc_led_blink_to);
iwm_mvm_led_disable(sc);
}
Index: head/sys/dev/iwm/if_iwm_mac_ctxt.c
===================================================================
--- head/sys/dev/iwm/if_iwm_mac_ctxt.c
+++ head/sys/dev/iwm/if_iwm_mac_ctxt.c
@@ -280,12 +280,24 @@
/*
* XXX should we error out if in_assoc is 1 and ni == NULL?
*/
+#if 0
if (in->in_assoc) {
IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
} else {
/* eth broadcast address */
- memset(cmd->bssid_addr, 0xff, sizeof(cmd->bssid_addr));
+ IEEE80211_ADDR_COPY(cmd->bssid_addr, ieee80211broadcastaddr);
}
+#else
+ /*
+ * XXX This workaround makes the firmware behave more correctly once
+ * we are associated, regularly giving us statistics notifications,
+ * as well as signaling missed beacons to us.
+ * Since we only call iwm_mvm_mac_ctxt_add() and
+ * iwm_mvm_mac_ctxt_changed() when already authenticating or
+ * associating, ni->ni_bssid should always make sense here.
+ */
+ IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
+#endif
/*
* Default to 2ghz if no node information is given.
@@ -457,13 +469,7 @@
iwm_mvm_mac_ctx_send(struct iwm_softc *sc, struct ieee80211vap *vap,
uint32_t action)
{
- int ret;
-
- ret = iwm_mvm_mac_ctxt_cmd_station(sc, vap, action);
- if (ret)
- return (ret);
-
- return (0);
+ return iwm_mvm_mac_ctxt_cmd_station(sc, vap, action);
}
int
@@ -489,17 +495,13 @@
iwm_mvm_mac_ctxt_changed(struct iwm_softc *sc, struct ieee80211vap *vap)
{
struct iwm_vap *iv = IWM_VAP(vap);
- int ret;
if (iv->is_uploaded == 0) {
device_printf(sc->sc_dev, "%s: called; uploaded = 0\n",
__func__);
return (EIO);
}
- ret = iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_MODIFY);
- if (ret)
- return (ret);
- return (0);
+ return iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_MODIFY);
}
#if 0
Index: head/sys/dev/iwm/if_iwm_pcie_trans.c
===================================================================
--- head/sys/dev/iwm/if_iwm_pcie_trans.c
+++ head/sys/dev/iwm/if_iwm_pcie_trans.c
@@ -256,13 +256,18 @@
IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000)
+ DELAY(2);
+
if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY
| IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 15000)) {
- rv = 1;
+ rv = 1;
} else {
/* jolt */
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET,
+ "%s: resetting device via NMI\n", __func__);
IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_FORCE_NMI);
}
@@ -343,13 +348,20 @@
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
@@ -413,8 +425,10 @@
IWM_DPRINTF(sc, IWM_DEBUG_RESET, "iwm apm start\n");
/* Disable L0S exit timer (platform NMI Work/Around) */
- IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
- IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ if (sc->sc_device_family != IWM_DEVICE_FAMILY_8000) {
+ IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
+ IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ }
/*
* Disable L0s without affecting L1;
@@ -435,7 +449,7 @@
iwm_apm_config(sc);
-#if 0 /* not for 7k */
+#if 0 /* not for 7k/8k */
/* Configure analog phase-lock-loop before activating to D0A */
if (trans->cfg->base_params->pll_cfg_val)
IWM_SETBITS(trans, IWM_CSR_ANA_PLL_CFG,
@@ -491,18 +505,19 @@
* do not disable clocks. This preserves any hardware bits already
* set by default in "CLK_CTRL_REG" after reset.
*/
- iwm_write_prph(sc, IWM_APMG_CLK_EN_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT);
- //kpause("iwmapm", 0, mstohz(20), NULL);
- DELAY(20);
-
- /* Disable L1-Active */
- iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
- IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
- /* Clear the interrupt in APMG if the NIC is in RFKILL */
- iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG,
- IWM_APMG_RTC_INT_STT_RFKILL);
-
+ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) {
+ iwm_write_prph(sc, IWM_APMG_CLK_EN_REG,
+ IWM_APMG_CLK_VAL_DMA_CLK_RQT);
+ DELAY(20);
+
+ /* Disable L1-Active */
+ iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
+ IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ /* Clear the interrupt in APMG if the NIC is in RFKILL */
+ iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG,
+ IWM_APMG_RTC_INT_STT_RFKILL);
+ }
out:
if (error)
device_printf(sc->sc_dev, "apm init error %d\n", error);
@@ -533,9 +548,7 @@
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)
Index: head/sys/dev/iwm/if_iwm_phy_ctxt.c
===================================================================
--- head/sys/dev/iwm/if_iwm_phy_ctxt.c
+++ head/sys/dev/iwm/if_iwm_phy_ctxt.c
@@ -202,8 +202,8 @@
ieee80211_chan2ieee(ic, chan),
chains_static,
chains_dynamic,
- IWM_FW_VALID_RX_ANT(sc),
- IWM_FW_VALID_TX_ANT(sc));
+ iwm_fw_valid_rx_ant(sc),
+ iwm_fw_valid_tx_ant(sc));
cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
@@ -217,13 +217,13 @@
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));
}
/*
Index: head/sys/dev/iwm/if_iwm_phy_db.c
===================================================================
--- head/sys/dev/iwm/if_iwm_phy_db.c
+++ head/sys/dev/iwm/if_iwm_phy_db.c
@@ -343,7 +343,6 @@
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);
}
@@ -374,6 +373,7 @@
return err;
}
+ DELAY(1000);
IWM_DPRINTF(sc, IWM_DEBUG_CMD,
"Sent PHY_DB HCMD, type = %d num = %d\n", type, i);
}
Index: head/sys/dev/iwm/if_iwm_power.c
===================================================================
--- head/sys/dev/iwm/if_iwm_power.c
+++ head/sys/dev/iwm/if_iwm_power.c
@@ -335,14 +335,3 @@
return ret;
}
-
-#if 0
-static 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
Index: head/sys/dev/iwm/if_iwm_scan.h
===================================================================
--- head/sys/dev/iwm/if_iwm_scan.h
+++ head/sys/dev/iwm/if_iwm_scan.h
@@ -106,8 +106,8 @@
#ifndef __IF_IWN_SCAN_H__
#define __IF_IWN_SCAN_H__
-extern int
-iwm_mvm_scan_request(struct iwm_softc *sc, int flags,
- int n_ssids, uint8_t *ssid, int ssid_len);
+extern int iwm_mvm_lmac_scan(struct iwm_softc *sc);
+extern int iwm_mvm_config_umac_scan(struct iwm_softc *);
+extern int iwm_mvm_umac_scan(struct iwm_softc *);
#endif /* __IF_IWN_SCAN_H__ */
Index: head/sys/dev/iwm/if_iwm_scan.c
===================================================================
--- head/sys/dev/iwm/if_iwm_scan.c
+++ head/sys/dev/iwm/if_iwm_scan.c
@@ -172,7 +172,7 @@
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;
@@ -180,6 +180,7 @@
return htole16(rx_chain);
}
+#if 0
static uint32_t
iwm_mvm_scan_max_out_time(struct iwm_softc *sc, uint32_t flags, int is_assoc)
{
@@ -197,15 +198,7 @@
return 0;
return htole32(SUSPEND_TIME_PERIOD);
}
-
-static 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);
-}
+#endif
static uint32_t
iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
@@ -216,7 +209,7 @@
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;
}
@@ -230,6 +223,7 @@
return htole32(IWM_RATE_6M_PLCP | tx_ant);
}
+#if 0
/*
* If req->n_ssids > 0, it means we should do an active scan.
* In case of active scan w/o directed scan, we receive a zero-length SSID
@@ -253,24 +247,30 @@
{
return (flags & IEEE80211_CHAN_2GHZ) ? 100 + 20 : 100 + 10;
}
+#endif
static int
-iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd,
- int flags, int n_ssids, int basic_ssid)
+iwm_mvm_scan_skip_channel(struct ieee80211_channel *c)
+{
+ if (IEEE80211_IS_CHAN_2GHZ(c) && IEEE80211_IS_CHAN_B(c))
+ return 0;
+ else if (IEEE80211_IS_CHAN_5GHZ(c) && IEEE80211_IS_CHAN_A(c))
+ return 0;
+ else
+ return 1;
+}
+
+static 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, j;
+ uint8_t nchan;
+ int j;
- if (!basic_ssid)
- type |= (1 << n_ssids);
-
- for (nchan = j = 0; j < ic->ic_nchans; j++) {
+ for (nchan = j = 0;
+ j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
c = &ic->ic_channels[j];
/* For 2GHz, only populate 11b channels */
/* For 5GHz, only populate 11a channels */
@@ -278,175 +278,458 @@
* Catch other channels, in case we have 900MHz channels or
* something in the chanlist.
*/
- if ((flags & IEEE80211_CHAN_2GHZ) && (! IEEE80211_IS_CHAN_B(c))) {
- continue;
- } else if ((flags & IEEE80211_CHAN_5GHZ) && (! IEEE80211_IS_CHAN_A(c))) {
+ if (iwm_mvm_scan_skip_channel(c)) {
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
+ "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
+ __func__, c->ic_freq, c->ic_ieee, c->ic_flags);
continue;
- } else {
+ }
+
+ IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
+ "Adding channel %d (%d Mhz) to the list\n",
+ nchan, c->ic_freq);
+ chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0));
+ chan->iter_count = htole16(1);
+ chan->iter_interval = htole32(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++;
+ }
+
+ return nchan;
+}
+
+static uint8_t
+iwm_mvm_umac_scan_fill_channels(struct iwm_softc *sc,
+ struct iwm_scan_channel_cfg_umac *chan, int n_ssids)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_channel *c;
+ uint8_t nchan;
+ int j;
+
+ for (nchan = j = 0;
+ j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
+ c = &ic->ic_channels[j];
+ /* For 2GHz, only populate 11b channels */
+ /* For 5GHz, only populate 11a channels */
+ /*
+ * Catch other channels, in case we have 900MHz channels or
+ * something in the chanlist.
+ */
+ if (iwm_mvm_scan_skip_channel(c)) {
IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
"%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
- __func__,
- c->ic_freq,
- c->ic_ieee,
- c->ic_flags);
+ __func__, c->ic_freq, c->ic_ieee, c->ic_flags);
+ continue;
}
+
IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
"Adding channel %d (%d Mhz) to the list\n",
- nchan, c->ic_freq);
- 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);
+ nchan, c->ic_freq);
+ chan->channel_num = ieee80211_mhz2ieee(c->ic_freq, 0);
+ chan->iter_count = 1;
+ chan->iter_interval = htole16(0);
+ chan->flags = htole32(0);
+#if 0 /* makes scanning while associated less useful */
+ if (n_ssids != 0)
+ chan->flags = htole32(1 << 0); /* select SSID 0 */
+#endif
chan++;
nchan++;
}
- if (nchan == 0)
- device_printf(sc->sc_dev,
- "%s: NO CHANNEL!\n", __func__);
+
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.
- */
-static 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)
-{
- 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;
+static int
+iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf;
+ struct ieee80211_rateset *rs;
+ size_t remain = sizeof(preq->buf);
+ uint8_t *frm, *pos;
+ int ssid_len = 0;
+ const uint8_t *ssid = NULL;
+
+ memset(preq, 0, sizeof(*preq));
+
+ /* Ensure enough space for header and SSID IE. */
+ if (remain < sizeof(*wh) + 2 + ssid_len)
+ return ENOBUFS;
- frame->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
+ /*
+ * Build a probe request frame. Most of the following code is a
+ * copy & paste of what is done in net80211.
+ */
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
IEEE80211_FC0_SUBTYPE_PROBE_REQ;
- frame->i_fc[1] = IEEE80211_FC1_DIR_NODS;
- IEEE80211_ADDR_COPY(frame->i_addr1, ieee80211broadcastaddr);
- IEEE80211_ADDR_COPY(frame->i_addr2, ta);
- IEEE80211_ADDR_COPY(frame->i_addr3, ieee80211broadcastaddr);
-
- /* for passive scans, no need to fill anything */
- if (n_ssids == 0)
- return sizeof(*frame);
-
- /* 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;
+ wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+ IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr);
+ IEEE80211_ADDR_COPY(wh->i_addr2, vap ? vap->iv_myaddr : ic->ic_macaddr);
+ IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr);
+ *(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, ssid, ssid_len);
+
+ /* 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 0
+ if (ic->ic_flags & IEEE80211_F_HTON) {
+ if (remain < 28)
+ return ENOBUFS;
+ frm = ieee80211_add_htcaps(frm, ic);
+ /* XXX add WME info? */
+ }
+#endif
+ preq->common_data.len = htole16(frm - pos);
+
+ return 0;
+}
+
+int
+iwm_mvm_config_umac_scan(struct iwm_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
- pos = ieee80211_add_ssid(pos, ssid, ssid_len);
+ struct iwm_scan_config *scan_config;
+ int ret, j, nchan;
+ size_t cmd_size;
+ struct ieee80211_channel *c;
+ struct iwm_host_cmd hcmd = {
+ .id = iwm_cmd_id(IWM_SCAN_CFG_CMD, IWM_ALWAYS_LONG_GROUP, 0),
+ .flags = IWM_CMD_SYNC,
+ };
+ static const uint32_t rates = (IWM_SCAN_CONFIG_RATE_1M |
+ IWM_SCAN_CONFIG_RATE_2M | IWM_SCAN_CONFIG_RATE_5M |
+ IWM_SCAN_CONFIG_RATE_11M | IWM_SCAN_CONFIG_RATE_6M |
+ IWM_SCAN_CONFIG_RATE_9M | IWM_SCAN_CONFIG_RATE_12M |
+ IWM_SCAN_CONFIG_RATE_18M | IWM_SCAN_CONFIG_RATE_24M |
+ IWM_SCAN_CONFIG_RATE_36M | IWM_SCAN_CONFIG_RATE_48M |
+ IWM_SCAN_CONFIG_RATE_54M);
+
+ cmd_size = sizeof(*scan_config) + sc->sc_capa_n_scan_channels;
+
+ scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (scan_config == NULL)
+ return ENOMEM;
+
+ scan_config->tx_chains = htole32(iwm_fw_valid_tx_ant(sc));
+ scan_config->rx_chains = htole32(iwm_fw_valid_rx_ant(sc));
+ scan_config->legacy_rates = htole32(rates |
+ IWM_SCAN_CONFIG_SUPPORTED_RATE(rates));
+
+ /* These timings correspond to iwlwifi's UNASSOC scan. */
+ scan_config->dwell_active = 10;
+ scan_config->dwell_passive = 110;
+ scan_config->dwell_fragmented = 44;
+ scan_config->dwell_extended = 90;
+ scan_config->out_of_channel_time = htole32(0);
+ scan_config->suspend_time = htole32(0);
+
+ IEEE80211_ADDR_COPY(scan_config->mac_addr,
+ vap ? vap->iv_myaddr : ic->ic_macaddr);
+
+ scan_config->bcast_sta_id = sc->sc_aux_sta.sta_id;
+ scan_config->channel_flags = IWM_CHANNEL_FLAG_EBS |
+ IWM_CHANNEL_FLAG_ACCURATE_EBS | IWM_CHANNEL_FLAG_EBS_ADD |
+ IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE;
- if (ie && ie_len && left >= ie_len) {
- memcpy(pos, ie, ie_len);
- pos += ie_len;
+ for (nchan = j = 0;
+ j < ic->ic_nchans && nchan < sc->sc_capa_n_scan_channels; j++) {
+ c = &ic->ic_channels[j];
+ /* For 2GHz, only populate 11b channels */
+ /* For 5GHz, only populate 11a channels */
+ /*
+ * Catch other channels, in case we have 900MHz channels or
+ * something in the chanlist.
+ */
+ if (iwm_mvm_scan_skip_channel(c))
+ continue;
+ scan_config->channel_array[nchan++] =
+ ieee80211_mhz2ieee(c->ic_freq, 0);
}
- return pos - (uint8_t *)frame;
+ scan_config->flags = htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE |
+ IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS |
+ IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS |
+ IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS |
+ IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID |
+ IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES |
+ IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES |
+ IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR |
+ IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS|
+ IWM_SCAN_CONFIG_N_CHANNELS(nchan) |
+ IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED);
+
+ hcmd.data[0] = scan_config;
+ hcmd.len[0] = cmd_size;
+
+ IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending UMAC scan config\n");
+
+ ret = iwm_send_cmd(sc, &hcmd);
+ if (!ret)
+ IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
+ "UMAC scan config was sent successfully\n");
+
+ free(scan_config, M_DEVBUF);
+ return ret;
}
int
-iwm_mvm_scan_request(struct iwm_softc *sc, int flags,
- int n_ssids, uint8_t *ssid, int ssid_len)
+iwm_mvm_umac_scan(struct iwm_softc *sc)
{
struct iwm_host_cmd hcmd = {
- .id = IWM_SCAN_REQUEST_CMD,
+ .id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_ALWAYS_LONG_GROUP, 0),
.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;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
- int is_assoc = 0;
+ struct iwm_scan_req_umac *req;
+ struct iwm_scan_req_umac_tail *tail;
+ size_t req_len;
+ int ssid_len = 0;
+ const uint8_t *ssid = NULL;
int ret;
- uint32_t status;
- int basic_ssid =
- !(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID);
- sc->sc_scanband = flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ);
+ req_len = sizeof(struct iwm_scan_req_umac) +
+ (sizeof(struct iwm_scan_channel_cfg_umac) *
+ sc->sc_capa_n_scan_channels) +
+ sizeof(struct iwm_scan_req_umac_tail);
+ if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
+ return ENOMEM;
+ req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (req == NULL)
+ return ENOMEM;
+
+ hcmd.len[0] = (uint16_t)req_len;
+ hcmd.data[0] = (void *)req;
+
+ IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n");
+
+ /* 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_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
+ req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
+
+ req->n_channels = iwm_mvm_umac_scan_fill_channels(sc,
+ (struct iwm_scan_channel_cfg_umac *)req->data, ssid_len != 0);
+
+ req->general_flags = htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL |
+ IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE |
+ IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL);
+
+ tail = (void *)((char *)&req->data +
+ sizeof(struct iwm_scan_channel_cfg_umac) *
+ sc->sc_capa_n_scan_channels);
+
+ /* Check if we're doing an active directed scan. */
+ if (ssid_len != 0) {
+ tail->direct_scan[0].id = IEEE80211_ELEMID_SSID;
+ tail->direct_scan[0].len = ssid_len;
+ memcpy(tail->direct_scan[0].ssid, ssid, ssid_len);
+ req->general_flags |=
+ htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT);
+ } else {
+ req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE);
+ }
+
+ if (isset(sc->sc_enabled_capa,
+ IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
+ req->general_flags |=
+ htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED);
+
+ ret = iwm_mvm_fill_probe_req(sc, &tail->preq);
+ if (ret) {
+ free(req, M_DEVBUF);
+ return ret;
+ }
+
+ /* Specify the scan plan: We'll do one iteration. */
+ tail->schedule[0].interval = 0;
+ tail->schedule[0].iter_count = 1;
+
+ ret = iwm_send_cmd(sc, &hcmd);
+ if (!ret)
+ IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
+ "Scan request was sent successfully\n");
+ free(req, M_DEVBUF);
+ return ret;
+}
+
+int
+iwm_mvm_lmac_scan(struct iwm_softc *sc)
+{
+ struct iwm_host_cmd hcmd = {
+ .id = IWM_SCAN_OFFLOAD_REQUEST_CMD,
+ .len = { 0, },
+ .data = { NULL, },
+ .flags = IWM_CMD_SYNC,
+ };
+ struct iwm_scan_req_lmac *req;
+ size_t req_len;
+ int ret;
+ int ssid_len = 0;
+ const uint8_t *ssid = NULL;
IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
"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);
+ 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_NOWAIT | M_ZERO);
+ if (req == NULL)
+ return ENOMEM;
+
+ hcmd.len[0] = (uint16_t)req_len;
+ hcmd.data[0] = (void *)req;
+
+ /* 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 (ssid_len == 0)
+ req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASSIVE);
+ else
+ req->scan_flags |=
+ htole32(IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION);
+ if (isset(sc->sc_enabled_capa,
+ IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
+ req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
+
+ req->flags = htole32(IWM_PHY_BAND_24);
+ if (sc->sc_nvm.sku_cap_band_52GHz_enable)
+ req->flags |= htole32(IWM_PHY_BAND_5);
+ req->filter_flags =
+ htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON);
- cmd->type = htole32(IWM_SCAN_TYPE_FORCED);
- cmd->repeats = htole32(1);
+ /* Tx flags 2 GHz. */
+ req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
+ IWM_TX_CMD_FLG_BT_DIS);
+ req->tx_cmd[0].rate_n_flags =
+ iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/);
+ req->tx_cmd[0].sta_id = sc->sc_aux_sta.sta_id;
- /*
- * If the user asked for passive scan, don't change to active scan if
- * you see any activity on the channel - remain passive.
- */
- if (n_ssids > 0) {
- cmd->passive2active = htole16(1);
- cmd->scan_flags |= IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
-#if 0
- if (basic_ssid) {
- ssid = req->ssids[0].ssid;
- ssid_len = req->ssids[0].ssid_len;
- }
-#endif
- } else {
- cmd->passive2active = 0;
- cmd->scan_flags &= ~IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
+ /* Tx flags 5 GHz. */
+ req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
+ IWM_TX_CMD_FLG_BT_DIS);
+ req->tx_cmd[1].rate_n_flags =
+ iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/);
+ req->tx_cmd[1].sta_id = sc->sc_aux_sta.sta_id;
+
+ /* Check if we're doing an active directed scan. */
+ if (ssid_len != 0) {
+ req->direct_scan[0].id = IEEE80211_ELEMID_SSID;
+ req->direct_scan[0].len = ssid_len;
+ memcpy(req->direct_scan[0].ssid, ssid, ssid_len);
}
- 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,
- vap ? vap->iv_myaddr : ic->ic_macaddr, 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) {
+ req->n_channels = iwm_mvm_lmac_scan_fill_channels(sc,
+ (struct iwm_scan_channel_cfg_lmac *)req->data,
+ ssid_len != 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);
+ return ret;
+ }
+
+ /* 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) {
IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
"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);
return ret;
}
Index: head/sys/dev/iwm/if_iwm_time_event.c
===================================================================
--- head/sys/dev/iwm/if_iwm_time_event.c
+++ head/sys/dev/iwm/if_iwm_time_event.c
@@ -257,8 +257,7 @@
htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_DEFAULT_MACID, IWM_DEFAULT_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);
@@ -268,7 +267,8 @@
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);
}
Index: head/sys/dev/iwm/if_iwm_util.h
===================================================================
--- head/sys/dev/iwm/if_iwm_util.h
+++ head/sys/dev/iwm/if_iwm_util.h
@@ -116,4 +116,7 @@
uint16_t len, const void *data, uint32_t *status);
extern void iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd);
+extern uint8_t iwm_fw_valid_tx_ant(struct iwm_softc *sc);
+extern uint8_t iwm_fw_valid_rx_ant(struct iwm_softc *sc);
+
#endif /* __IF_IWM_UTIL_H__ */
Index: head/sys/dev/iwm/if_iwm_util.c
===================================================================
--- head/sys/dev/iwm/if_iwm_util.c
+++ head/sys/dev/iwm/if_iwm_util.c
@@ -169,7 +169,7 @@
{
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 = NULL;
struct iwm_device_cmd *cmd;
struct mbuf *m;
bus_dma_segment_t seg;
@@ -178,11 +178,15 @@
int error = 0, i, paylen, off;
int code;
int async, wantresp;
+ int group_id;
int nsegs;
+ size_t hdrlen, datasz;
+ uint8_t *data;
code = hcmd->id;
async = hcmd->flags & IWM_CMD_ASYNC;
wantresp = hcmd->flags & IWM_CMD_WANT_SKB;
+ data = NULL;
for (i = 0, paylen = 0; i < nitems(hcmd->len); i++) {
paylen += hcmd->len[i];
@@ -207,17 +211,27 @@
}
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) {
IWM_DPRINTF(sc, IWM_DEBUG_CMD,
"large command paylen=%u len0=%u\n",
paylen, hcmd->len[0]);
/* Command is too large */
+ size_t totlen = hdrlen + paylen;
if (paylen > IWM_MAX_CMD_PAYLOAD_SIZE) {
device_printf(sc->sc_dev,
"firmware command too long (%zd bytes)\n",
- paylen + sizeof(cmd->hdr));
+ totlen);
error = EINVAL;
goto out;
}
@@ -229,30 +243,41 @@
m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
- data->map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
+ txdata->map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: can't map mbuf, error %d\n", __func__, error);
m_freem(m);
goto out;
}
- data->m = m; /* mbuf will be freed in iwm_cmd_done() */
+ txdata->m = m; /* mbuf will be freed in iwm_cmd_done() */
cmd = mtod(m, struct iwm_device_cmd *);
paddr = seg.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 = iwm_cmd_opcode(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, ("off %d != paylen %d", off, paylen));
@@ -261,18 +286,17 @@
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;
IWM_DPRINTF(sc, IWM_DEBUG_CMD,
- "%s: iwm_send_cmd 0x%x size=%lu %s\n",
- __func__,
+ "iwm_send_cmd 0x%x size=%lu %s\n",
code,
- (unsigned long) (hcmd->len[0] + hcmd->len[1] + sizeof(cmd->hdr)),
+ (unsigned long) (hcmd->len[0] + hcmd->len[1] + hdrlen),
async ? " (async)" : "");
- if (paylen > sizeof(cmd->data)) {
- bus_dmamap_sync(ring->data_dmat, data->map,
+ if (paylen > datasz) {
+ bus_dmamap_sync(ring->data_dmat, txdata->map,
BUS_DMASYNC_PREWRITE);
} else {
bus_dmamap_sync(ring->cmd_dma.tag, ring->cmd_dma.map,
@@ -404,3 +428,31 @@
sc->sc_wantresp = -1;
wakeup(&sc->sc_wantresp);
}
+
+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);
+
+ if (sc->sc_nvm.valid_rx_ant)
+ rx_ant &= sc->sc_nvm.valid_rx_ant;
+
+ return rx_ant;
+}
Index: head/sys/dev/iwm/if_iwmreg.h
===================================================================
--- head/sys/dev/iwm/if_iwmreg.h
+++ head/sys/dev/iwm/if_iwmreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwmreg.h,v 1.3 2015/02/23 10:25:20 stsp Exp $ */
+/* $OpenBSD: if_iwmreg.h,v 1.4 2015/06/15 08:06:11 stsp Exp $ */
/* $FreeBSD$ */
/******************************************************************************
@@ -136,6 +136,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 */
@@ -182,6 +185,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*/
@@ -308,6 +313,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 */
@@ -402,6 +408,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 */
@@ -421,19 +428,37 @@
IWM_CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010,
};
-#define IWM_CSR_UCODE_LOAD_STATUS_ADDR (0x100)
+#define IWM_FH_UCODE_LOAD_STATUS 0x1af0
+#define IWM_CSR_UCODE_LOAD_STATUS_ADDR 0x1e70
enum iwm_secure_load_status_reg {
- IWM_CSR_CPU_STATUS_LOADING_STARTED = 0x00000001,
- IWM_CSR_CPU_STATUS_LOADING_COMPLETED = 0x00000002,
- IWM_CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8,
- IWM_CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00,
-};
-
-#define IWM_CSR_SECURE_INSPECTOR_CODE_ADDR (0x100)
-#define IWM_CSR_SECURE_INSPECTOR_DATA_ADDR (0x100)
+ IWM_LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001,
+ IWM_LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003,
+ IWM_LMPM_CPU_UCODE_LOADING_COMPLETED = 0x00000007,
+ IWM_LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8,
+ IWM_LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00,
+};
+#define IWM_FH_MEM_TB_MAX_LENGTH 0x20000
+
+#define IWM_LMPM_SECURE_INSPECTOR_CODE_ADDR 0x1e38
+#define IWM_LMPM_SECURE_INSPECTOR_DATA_ADDR 0x1e3c
+#define IWM_LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR 0x1e78
+#define IWM_LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR 0x1e7c
+
+#define IWM_LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE 0x400000
+#define IWM_LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE 0x402000
+#define IWM_LMPM_SECURE_CPU1_HDR_MEM_SPACE 0x420000
+#define IWM_LMPM_SECURE_CPU2_HDR_MEM_SPACE 0x420400
#define IWM_CSR_SECURE_TIME_OUT (100)
+/* extended range in FW SRAM */
+#define IWM_FW_MEM_EXTENDED_START 0x40000
+#define IWM_FW_MEM_EXTENDED_END 0x57FFF
+
+/* FW chicken bits */
+#define IWM_LMPM_CHICK 0xa01ff8
+#define IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE 0x01
+
#define IWM_FH_TCSR_0_REG0 (0x1D00)
/*
@@ -484,6 +509,32 @@
#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)
@@ -567,7 +618,12 @@
* 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),
@@ -590,8 +646,150 @@
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_ENERG \
+Y\12TIME_EVENT_V2\13D3_6_IPV6\14BF_UPDATED\15NO_BASIC_SSID\17D3_CONTINUITY\20NEW_NSOFF \
+L_S\21NEW_NSOFFL_L\22SCHED_SCAN\24STA_KEY_CMD\25DEVICE_PS_CMD\26P2P_PS\27P2P_PS_DCM\30 \
+P2P_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 */
@@ -617,8 +815,8 @@
* 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)
@@ -765,7 +963,17 @@
* 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 {
@@ -774,6 +982,16 @@
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 {
@@ -846,7 +1064,19 @@
#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
+#define IWM_DEVICE_SET_NMI_8000_REG 0x00a01c24
+#define IWM_DEVICE_SET_NMI_8000_VAL 0x1000000
+
+/*
+ * Device reset for family 8000
+ * write to bit 24 in order to reset the CPU
+ */
+#define IWM_RELEASE_CPU_RESET 0x300c
+#define IWM_RELEASE_CPU_RESET_BIT 0x1000000
+
/*****************************************************************************
* 7000/3000 series SHR DTS addresses *
@@ -960,6 +1190,8 @@
#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)
@@ -993,6 +1225,8 @@
#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)
{
@@ -1510,13 +1744,14 @@
* BEGIN mvm/fw-api.h
*/
-/* 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 {
@@ -1541,6 +1776,13 @@
IWM_PHY_CONTEXT_CMD = 0x8,
IWM_DBG_CFG = 0x9,
+ /* UMAC scan commands */
+ IWM_SCAN_ITERATION_COMPLETE_UMAC = 0xb5,
+ IWM_SCAN_CFG_CMD = 0xc,
+ IWM_SCAN_REQ_UMAC = 0xd,
+ IWM_SCAN_ABORT_UMAC = 0xe,
+ IWM_SCAN_COMPLETE_UMAC = 0xf,
+
/* station table */
IWM_ADD_STA_KEY = 0x17,
IWM_ADD_STA = 0x18,
@@ -1551,6 +1793,9 @@
IWM_TXPATH_FLUSH = 0x1e,
IWM_MGMT_MCAST_KEY = 0x1f,
+ /* scheduler config */
+ IWM_SCD_QUEUE_CFG = 0x1d,
+
/* global key */
IWM_WEP_KEY = 0x20,
@@ -1574,10 +1819,12 @@
/* 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,
@@ -1616,6 +1863,8 @@
IWM_MISSED_BEACONS_NOTIFICATION = 0xa2,
+ IWM_MFUART_LOAD_NOTIFICATION = 0xb1,
+
/* Power - new power table command */
IWM_MAC_PM_POWER_TABLE = 0xa9,
@@ -1623,6 +1872,10 @@
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,
@@ -1632,6 +1885,10 @@
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,
@@ -1800,10 +2057,14 @@
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,
+ /* 7, 8, 9 unknown */
+ IWM_NVM_SECTION_TYPE_HW_8000 = 10,
+ IWM_NVM_SECTION_TYPE_MAC_OVERRIDE,
+ IWM_NVM_SECTION_TYPE_PHY_SKU,
IWM_NVM_NUM_OF_SECTIONS,
};
@@ -1874,7 +2135,7 @@
#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;
@@ -1896,6 +2157,59 @@
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,
@@ -2055,6 +2369,7 @@
IWM_TE_V1_NOTIF_HOST_FRAG_END = (1 << 5),
IWM_TE_V1_NOTIF_INTERNAL_FRAG_START = (1 << 6),
IWM_TE_V1_NOTIF_INTERNAL_FRAG_END = (1 << 7),
+ IWM_T2_V2_START_IMMEDIATELY = (1 << 11),
}; /* IWM_MAC_EVENT_ACTION_API_E_VER_2 */
@@ -2608,6 +2923,21 @@
} __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
@@ -2884,6 +3214,18 @@
#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 */
@@ -2898,6 +3240,8 @@
#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 +4710,46 @@
* BEGIN mvm/fw-api-scan.h
*/
+/**
+ * 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 +4814,23 @@
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 +4874,194 @@
#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 interval in usecs (suspend before executing)
- * bits 20-23: reserved
- * bits 24-31: number of beacons (suspend between channels)
- * @rxon_flags: RXON_FLG_*
- * @filter_flags: RXON_FILTER_*
- * @tx_cmd: for active scans (zero for passive), w/o payload,
- * no RS so specify TX rate
- * @direct_scan: direct scan SSIDs
- * @type: one of IWM_SCAN_TYPE_*
- * @repeats: how many time to repeat the scan
+ * iwm_scan_schedule_lmac - schedule of scan offload
+ * @delay: delay between iterations, in seconds.
+ * @iterations: num of scan iterations
+ * @full_scan_mul: number of partial scans before each full scan
*/
-struct iwm_scan_cmd {
+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 +5184,6 @@
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 +5379,28 @@
};
/**
+ * 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
@@ -4895,11 +5432,336 @@
* BEGIN mvm/fw-api-sta.h
*/
+/* UMAC Scan API */
+
+/* The maximum of either of these cannot exceed 8, because we use an
+ * 8-bit mask (see IWM_MVM_SCAN_MASK).
+ */
+#define IWM_MVM_MAX_UMAC_SCANS 8
+#define IWM_MVM_MAX_LMAC_SCANS 1
+
+enum iwm_scan_config_flags {
+ IWM_SCAN_CONFIG_FLAG_ACTIVATE = (1 << 0),
+ IWM_SCAN_CONFIG_FLAG_DEACTIVATE = (1 << 1),
+ IWM_SCAN_CONFIG_FLAG_FORBID_CHUB_REQS = (1 << 2),
+ IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS = (1 << 3),
+ IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS = (1 << 8),
+ IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS = (1 << 9),
+ IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID = (1 << 10),
+ IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES = (1 << 11),
+ IWM_SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES = (1 << 12),
+ IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS = (1 << 13),
+ IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES = (1 << 14),
+ IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR = (1 << 15),
+ IWM_SCAN_CONFIG_FLAG_SET_FRAGMENTED = (1 << 16),
+ IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED = (1 << 17),
+ IWM_SCAN_CONFIG_FLAG_SET_CAM_MODE = (1 << 18),
+ IWM_SCAN_CONFIG_FLAG_CLEAR_CAM_MODE = (1 << 19),
+ IWM_SCAN_CONFIG_FLAG_SET_PROMISC_MODE = (1 << 20),
+ IWM_SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE = (1 << 21),
+
+ /* Bits 26-31 are for num of channels in channel_array */
+#define IWM_SCAN_CONFIG_N_CHANNELS(n) ((n) << 26)
+};
+
+enum iwm_scan_config_rates {
+ /* OFDM basic rates */
+ IWM_SCAN_CONFIG_RATE_6M = (1 << 0),
+ IWM_SCAN_CONFIG_RATE_9M = (1 << 1),
+ IWM_SCAN_CONFIG_RATE_12M = (1 << 2),
+ IWM_SCAN_CONFIG_RATE_18M = (1 << 3),
+ IWM_SCAN_CONFIG_RATE_24M = (1 << 4),
+ IWM_SCAN_CONFIG_RATE_36M = (1 << 5),
+ IWM_SCAN_CONFIG_RATE_48M = (1 << 6),
+ IWM_SCAN_CONFIG_RATE_54M = (1 << 7),
+ /* CCK basic rates */
+ IWM_SCAN_CONFIG_RATE_1M = (1 << 8),
+ IWM_SCAN_CONFIG_RATE_2M = (1 << 9),
+ IWM_SCAN_CONFIG_RATE_5M = (1 << 10),
+ IWM_SCAN_CONFIG_RATE_11M = (1 << 11),
+
+ /* Bits 16-27 are for supported rates */
+#define IWM_SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16)
+};
+
+enum iwm_channel_flags {
+ IWM_CHANNEL_FLAG_EBS = (1 << 0),
+ IWM_CHANNEL_FLAG_ACCURATE_EBS = (1 << 1),
+ IWM_CHANNEL_FLAG_EBS_ADD = (1 << 2),
+ IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE = (1 << 3),
+};
+
+/**
+ * struct iwm_scan_config
+ * @flags: enum scan_config_flags
+ * @tx_chains: valid_tx antenna - ANT_* definitions
+ * @rx_chains: valid_rx antenna - ANT_* definitions
+ * @legacy_rates: default legacy rates - enum scan_config_rates
+ * @out_of_channel_time: default max out of serving channel time
+ * @suspend_time: default max suspend time
+ * @dwell_active: default dwell time for active scan
+ * @dwell_passive: default dwell time for passive scan
+ * @dwell_fragmented: default dwell time for fragmented scan
+ * @dwell_extended: default dwell time for channels 1, 6 and 11
+ * @mac_addr: default mac address to be used in probes
+ * @bcast_sta_id: the index of the station in the fw
+ * @channel_flags: default channel flags - enum iwm_channel_flags
+ * scan_config_channel_flag
+ * @channel_array: default supported channels
+ */
+struct iwm_scan_config {
+ uint32_t flags;
+ uint32_t tx_chains;
+ uint32_t rx_chains;
+ uint32_t legacy_rates;
+ uint32_t out_of_channel_time;
+ uint32_t suspend_time;
+ uint8_t dwell_active;
+ uint8_t dwell_passive;
+ uint8_t dwell_fragmented;
+ uint8_t dwell_extended;
+ uint8_t mac_addr[IEEE80211_ADDR_LEN];
+ uint8_t bcast_sta_id;
+ uint8_t channel_flags;
+ uint8_t channel_array[];
+} __packed; /* SCAN_CONFIG_DB_CMD_API_S */
+
+/**
+ * iwm_umac_scan_flags
+ *@IWM_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request
+ * can be preempted by other scan requests with higher priority.
+ * The low priority scan will be resumed when the higher proirity scan is
+ * completed.
+ *@IWM_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver
+ * when scan starts.
+ */
+enum iwm_umac_scan_flags {
+ IWM_UMAC_SCAN_FLAG_PREEMPTIVE = (1 << 0),
+ IWM_UMAC_SCAN_FLAG_START_NOTIF = (1 << 1),
+};
+
+enum iwm_umac_scan_uid_offsets {
+ IWM_UMAC_SCAN_UID_TYPE_OFFSET = 0,
+ IWM_UMAC_SCAN_UID_SEQ_OFFSET = 8,
+};
+
+enum iwm_umac_scan_general_flags {
+ IWM_UMAC_SCAN_GEN_FLAGS_PERIODIC = (1 << 0),
+ IWM_UMAC_SCAN_GEN_FLAGS_OVER_BT = (1 << 1),
+ IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL = (1 << 2),
+ IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE = (1 << 3),
+ IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT = (1 << 4),
+ IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE = (1 << 5),
+ IWM_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID = (1 << 6),
+ IWM_UMAC_SCAN_GEN_FLAGS_FRAGMENTED = (1 << 7),
+ IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = (1 << 8),
+ IWM_UMAC_SCAN_GEN_FLAGS_MATCH = (1 << 9),
+ IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL = (1 << 10),
+};
+
+/**
+ * struct iwm_scan_channel_cfg_umac
+ * @flags: bitmap - 0-19: directed scan to i'th ssid.
+ * @channel_num: channel number 1-13 etc.
+ * @iter_count: repetition count for the channel.
+ * @iter_interval: interval between two scan iterations on one channel.
+ */
+struct iwm_scan_channel_cfg_umac {
+ uint32_t flags;
+ uint8_t channel_num;
+ uint8_t iter_count;
+ uint16_t iter_interval;
+} __packed; /* SCAN_CHANNEL_CFG_S_VER2 */
+
+/**
+ * struct iwm_scan_umac_schedule
+ * @interval: interval in seconds between scan iterations
+ * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop
+ * @reserved: for alignment and future use
+ */
+struct iwm_scan_umac_schedule {
+ uint16_t interval;
+ uint8_t iter_count;
+ uint8_t reserved;
+} __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */
+
+/**
+ * struct iwm_scan_req_umac_tail - the rest of the UMAC scan request command
+ * parameters following channels configuration array.
+ * @schedule: two scheduling plans.
+ * @delay: delay in TUs before starting the first scan iteration
+ * @reserved: for future use and alignment
+ * @preq: probe request with IEs blocks
+ * @direct_scan: list of SSIDs for directed active scan
+ */
+struct iwm_scan_req_umac_tail {
+ /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */
+ struct iwm_scan_umac_schedule schedule[IWM_MAX_SCHED_SCAN_PLANS];
+ uint16_t delay;
+ uint16_t reserved;
+ /* SCAN_PROBE_PARAMS_API_S_VER_1 */
+ struct iwm_scan_probe_req preq;
+ struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX];
+} __packed;
+
+/**
+ * struct iwm_scan_req_umac
+ * @flags: &enum iwm_umac_scan_flags
+ * @uid: scan id, &enum iwm_umac_scan_uid_offsets
+ * @ooc_priority: out of channel priority - &enum iwm_scan_priority
+ * @general_flags: &enum iwm_umac_scan_general_flags
+ * @extended_dwell: dwell time for channels 1, 6 and 11
+ * @active_dwell: dwell time for active scan
+ * @passive_dwell: dwell time for passive scan
+ * @fragmented_dwell: dwell time for fragmented passive scan
+ * @max_out_time: max out of serving channel time
+ * @suspend_time: max suspend time
+ * @scan_priority: scan internal prioritization &enum iwm_scan_priority
+ * @channel_flags: &enum iwm_scan_channel_flags
+ * @n_channels: num of channels in scan request
+ * @reserved: for future use and alignment
+ * @data: &struct iwm_scan_channel_cfg_umac and
+ * &struct iwm_scan_req_umac_tail
+ */
+struct iwm_scan_req_umac {
+ uint32_t flags;
+ uint32_t uid;
+ uint32_t ooc_priority;
+ /* SCAN_GENERAL_PARAMS_API_S_VER_1 */
+ uint32_t general_flags;
+ uint8_t extended_dwell;
+ uint8_t active_dwell;
+ uint8_t passive_dwell;
+ uint8_t fragmented_dwell;
+ uint32_t max_out_time;
+ uint32_t suspend_time;
+ uint32_t scan_priority;
+ /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
+ uint8_t channel_flags;
+ uint8_t n_channels;
+ uint16_t reserved;
+ uint8_t data[];
+} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */
+
+/**
+ * struct iwm_umac_scan_abort
+ * @uid: scan id, &enum iwm_umac_scan_uid_offsets
+ * @flags: reserved
+ */
+struct iwm_umac_scan_abort {
+ uint32_t uid;
+ uint32_t flags;
+} __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */
+
+/**
+ * struct iwm_umac_scan_complete
+ * @uid: scan id, &enum iwm_umac_scan_uid_offsets
+ * @last_schedule: last scheduling line
+ * @last_iter: last scan iteration number
+ * @scan status: &enum iwm_scan_offload_complete_status
+ * @ebs_status: &enum iwm_scan_ebs_status
+ * @time_from_last_iter: time elapsed from last iteration
+ * @reserved: for future use
+ */
+struct iwm_umac_scan_complete {
+ uint32_t uid;
+ uint8_t last_schedule;
+ uint8_t last_iter;
+ uint8_t status;
+ uint8_t ebs_status;
+ uint32_t time_from_last_iter;
+ uint32_t reserved;
+} __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */
+
+#define IWM_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 5
+/**
+ * struct iwm_scan_offload_profile_match - match information
+ * @bssid: matched bssid
+ * @channel: channel where the match occurred
+ * @energy:
+ * @matching_feature:
+ * @matching_channels: bitmap of channels that matched, referencing
+ * the channels passed in tue scan offload request
+ */
+struct iwm_scan_offload_profile_match {
+ uint8_t bssid[IEEE80211_ADDR_LEN];
+ uint16_t reserved;
+ uint8_t channel;
+ uint8_t energy;
+ uint8_t matching_feature;
+ uint8_t matching_channels[IWM_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN];
+} __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_1 */
+
+/**
+ * struct iwm_scan_offload_profiles_query - match results query response
+ * @matched_profiles: bitmap of matched profiles, referencing the
+ * matches passed in the scan offload request
+ * @last_scan_age: age of the last offloaded scan
+ * @n_scans_done: number of offloaded scans done
+ * @gp2_d0u: GP2 when D0U occurred
+ * @gp2_invoked: GP2 when scan offload was invoked
+ * @resume_while_scanning: not used
+ * @self_recovery: obsolete
+ * @reserved: reserved
+ * @matches: array of match information, one for each match
+ */
+struct iwm_scan_offload_profiles_query {
+ uint32_t matched_profiles;
+ uint32_t last_scan_age;
+ uint32_t n_scans_done;
+ uint32_t gp2_d0u;
+ uint32_t gp2_invoked;
+ uint8_t resume_while_scanning;
+ uint8_t self_recovery;
+ uint16_t reserved;
+ struct iwm_scan_offload_profile_match matches[IWM_SCAN_MAX_PROFILES];
+} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */
+
+/**
+ * struct iwm_umac_scan_iter_complete_notif - notifies end of scanning iteration
+ * @uid: scan id, &enum iwm_umac_scan_uid_offsets
+ * @scanned_channels: number of channels scanned and number of valid elements in
+ * results array
+ * @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: array of scan results, only "scanned_channels" of them are valid
+ */
+struct iwm_umac_scan_iter_complete_notif {
+ uint32_t uid;
+ 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; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_1 */
+
+/* Please keep this enum *SORTED* by hex value.
+ * Needed for binary search, otherwise a warning will be triggered.
+ */
+enum iwm_scan_subcmd_ids {
+ IWM_GSCAN_START_CMD = 0x0,
+ IWM_GSCAN_STOP_CMD = 0x1,
+ IWM_GSCAN_SET_HOTLIST_CMD = 0x2,
+ IWM_GSCAN_RESET_HOTLIST_CMD = 0x3,
+ IWM_GSCAN_SET_SIGNIFICANT_CHANGE_CMD = 0x4,
+ IWM_GSCAN_RESET_SIGNIFICANT_CHANGE_CMD = 0x5,
+ IWM_GSCAN_SIGNIFICANT_CHANGE_EVENT = 0xFD,
+ IWM_GSCAN_HOTLIST_CHANGE_EVENT = 0xFE,
+ IWM_GSCAN_RESULTS_AVAILABLE_EVENT = 0xFF,
+};
+
+/* 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
@@ -4923,10 +5785,7 @@
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),
@@ -5004,7 +5863,7 @@
/**
* 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
@@ -5014,7 +5873,7 @@
* @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),
@@ -5031,11 +5890,14 @@
* @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 */
@@ -5083,23 +5945,25 @@
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[IEEE80211_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.
@@ -5123,40 +5987,9 @@
* 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 {
+struct iwm_mvm_add_sta_cmd_v7 {
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[IEEE80211_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 {
- 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[IEEE80211_ADDR_LEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */
@@ -5174,7 +6007,7 @@
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
@@ -5264,17 +6097,228 @@
struct iwm_mvm_wep_key wep_key[0];
} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */
-
/*
* END mvm/fw-api-sta.h
*/
/*
+ * 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
*/
#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;
@@ -5282,6 +6326,16 @@
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,
@@ -5292,10 +6346,26 @@
#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 {
@@ -5357,11 +6427,4 @@
bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
-#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)
-
#endif /* __IF_IWM_REG_H__ */
Index: head/sys/dev/iwm/if_iwmvar.h
===================================================================
--- head/sys/dev/iwm/if_iwmvar.h
+++ head/sys/dev/iwm/if_iwmvar.h
@@ -137,8 +137,9 @@
(1 << IEEE80211_RADIOTAP_CHANNEL))
-#define IWM_UCODE_SECT_MAX 6
+#define IWM_UCODE_SECT_MAX 16
#define IWM_FWDMASEGSZ (192*1024)
+#define IWM_FWDMASEGSZ_8000 (320*1024)
/* sanity check value */
#define IWM_FWMAXSIZE (2*1024*1024)
@@ -152,9 +153,10 @@
#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
};
@@ -197,8 +199,9 @@
uint8_t radio_cfg_pnum;
uint8_t valid_tx_ant, valid_rx_ant;
#define IWM_NUM_CHANNELS 39
+#define IWM_NUM_CHANNELS_8000 51
- uint16_t nvm_ch_flags[IWM_NUM_CHANNELS];
+ uint16_t nvm_ch_flags[IWM_NUM_CHANNELS_8000];
uint16_t nvm_version;
uint8_t max_tx_pwr_half_dbm;
@@ -216,9 +219,9 @@
int handler_status;
uint32_t flags;
+ uint32_t id;
uint16_t len[IWM_MAX_CMD_TBS_PER_TFD];
uint8_t dataflags[IWM_MAX_CMD_TBS_PER_TFD];
- uint8_t id;
};
/*
@@ -269,13 +272,6 @@
#define IWM_MAX_SCATTER 20
-struct iwm_softc;
-struct iwm_rbuf {
- struct iwm_softc *sc;
- void *vaddr;
- bus_addr_t paddr;
-};
-
struct iwm_rx_data {
struct mbuf *m;
bus_dmamap_t map;
@@ -296,6 +292,7 @@
struct iwm_ucode_status {
uint32_t uc_error_event_table;
+ uint32_t uc_umac_error_event_table;
uint32_t uc_log_event_table;
int uc_ok;
@@ -304,7 +301,9 @@
#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_OTP_LOW_IMAGE_SIZE_FAMILY_8000 32768
#define IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500
#define IWM_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400
@@ -329,7 +328,7 @@
* iwlwifi/iwl-phy-db
*/
-#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 {
@@ -386,6 +385,7 @@
#define IWM_NODE(_ni) ((struct iwm_node *)(_ni))
#define IWM_STATION_ID 0
+#define IWM_AUX_STA_ID 1
#define IWM_DEFAULT_MACID 0
#define IWM_DEFAULT_COLOR 0
@@ -409,7 +409,7 @@
#define IWM_FLAG_STOPPED (1 << 2)
#define IWM_FLAG_RFKILL (1 << 3)
#define IWM_FLAG_BUSY (1 << 4)
-#define IWM_FLAG_DORESUME (1 << 5)
+#define IWM_FLAG_SCANNING (1 << 5)
struct intr_config_hook sc_preinit_hook;
struct callout sc_watchdog_to;
@@ -441,7 +441,14 @@
int ict_cur;
int sc_hw_rev;
+#define IWM_SILICON_A_STEP 0
+#define IWM_SILICON_B_STEP 1
+#define IWM_SILICON_C_STEP 2
+#define IWM_SILICON_D_STEP 3
int sc_hw_id;
+ int sc_device_family;
+#define IWM_DEVICE_FAMILY_7000 1
+#define IWM_DEVICE_FAMILY_8000 2
struct iwm_dma_info kw_dma;
struct iwm_dma_info fw_dma;
@@ -451,10 +458,14 @@
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;
@@ -482,10 +493,7 @@
int sc_tx_timer;
- 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;

File Metadata

Mime Type
text/plain
Expires
Thu, Feb 12, 12:40 PM (6 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28666786
Default Alt Text
D6967.diff (182 KB)

Event Timeline