Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144711053
D6967.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
182 KB
Referenced Files
None
Subscribers
None
D6967.diff
View Options
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, ®ulatory[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
Details
Attached
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)
Attached To
Mode
D6967: Sync iwm against dfbsd
Attached
Detach File
Event Timeline
Log In to Comment