diff --git a/share/man/man4/iwm.4 b/share/man/man4/iwm.4 index 9f67a3a623a7..7edc55007bdb 100644 --- a/share/man/man4/iwm.4 +++ b/share/man/man4/iwm.4 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 29, 2017 +.Dd November 5, 2019 .Dt IWM 4 .Os .Sh NAME @@ -51,6 +51,8 @@ Choose one from: .Cd "device iwm7265fw" .Cd "device iwm8000Cfw" .Cd "device iwm8265fw" +.Cd "device iwm9000fw" +.Cd "device iwm9260fw" .Ed .Pp Or you can use @@ -71,6 +73,8 @@ iwm7260fw_load="YES" iwm7265fw_load="YES" iwm8000Cfw_load="YES" iwm8265fw_load="YES" +iwm9000fw_load="YES" +iwm9260fw_load="YES" .Ed .Sh DESCRIPTION The @@ -84,6 +88,10 @@ driver provides support for: .It Intel Dual Band Wireless AC 7260 .It Intel Dual Band Wireless AC 7265 .It Intel Dual Band Wireless AC 8260 +.It Intel Dual Band Wireless AC 9260 +.It Intel Dual Band Wireless AC 9270 +.It Intel Dual Band Wireless AC 946X +.It Intel Dual Band Wireless AC 9560 .El .Pp .Nm diff --git a/share/man/man4/iwmfw.4 b/share/man/man4/iwmfw.4 index 01829ac75dd8..92e6ba9630bf 100644 --- a/share/man/man4/iwmfw.4 +++ b/share/man/man4/iwmfw.4 @@ -22,7 +22,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 29, 2017 +.Dd November 1, 2019 .Dt IWMFW 4 .Os .Sh NAME @@ -48,10 +48,12 @@ of the following: .Cd "device iwm7265fw" .Cd "device iwm8000Cfw" .Cd "device iwm8265fw" +.Cd "device iwm9000fw" +.Cd "device iwm9260fw" .Ed .Pp Alternatively, to load the driver as a -module at boot time, place the following line in +module at boot time, place one of the following lines in .Xr loader.conf 5 : .Bd -literal -offset indent iwm3160fw_load="YES" @@ -61,13 +63,14 @@ iwm7265fw_load="YES" iwm7265Dfw_load="YES" iwm8000Cfw_load="YES" iwm8265fw_load="YES" +iwm9000fw_load="YES" +iwm9260fw_load="YES" .Ed .Sh DESCRIPTION This module provides access to firmware sets for the -Intel Dual Band Wireless WiFi 3160, 3165, 3168, 7260, 7265, 8000, and 8260 series of -IEEE 802.11n/11ac adapters. -It may be -statically linked into the kernel, or loaded as a module. +Intel Dual Band Wireless WiFi 3160, 3165, 3168, 7260, 7265, 8000, 8260, +9000 and 9260 series of IEEE 802.11n/11ac adapters. +It may be statically linked into the kernel, or loaded as a module. .Sh SEE ALSO .Xr iwm 4 , .Xr firmware 9 diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index 067768dcd0f8..b82724907e4a 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -322,16 +322,14 @@ static int iwm_mvm_load_ucode_wait_alive(struct iwm_softc *, static int iwm_run_init_mvm_ucode(struct iwm_softc *, int); static int iwm_mvm_config_ltr(struct iwm_softc *sc); static int iwm_rx_addbuf(struct iwm_softc *, int, int); -static int iwm_mvm_get_signal_strength(struct iwm_softc *, - struct iwm_rx_phy_info *); static void iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *); static int iwm_get_noise(struct iwm_softc *, const struct iwm_mvm_statistics_rx_non_phy *); static void iwm_mvm_handle_rx_statistics(struct iwm_softc *, struct iwm_rx_packet *); -static boolean_t iwm_mvm_rx_rx_mpdu(struct iwm_softc *, struct mbuf *, - uint32_t, boolean_t); +static bool iwm_mvm_rx_mpdu(struct iwm_softc *, struct mbuf *, + uint32_t, bool); static int iwm_mvm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_node *); @@ -793,7 +791,7 @@ iwm_read_firmware(struct iwm_softc *sc) break; } - case 48: /* undocumented TLV */ + case IWM_UCODE_TLV_CMD_VERSIONS: case IWM_UCODE_TLV_SDIO_ADMA_ADDR: case IWM_UCODE_TLV_FW_GSCAN_CAPA: /* ignore, not used by current driver */ @@ -864,10 +862,9 @@ iwm_read_firmware(struct iwm_softc *sc) default: device_printf(sc->sc_dev, - "%s: unknown firmware section %d, abort\n", + "%s: unknown firmware section %d\n", __func__, tlv_type); - error = EINVAL; - goto parse_out; + break; } } @@ -929,19 +926,28 @@ static int iwm_alloc_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) { bus_size_t size; - int i, error; + size_t descsz; + int count, i, error; ring->cur = 0; + if (sc->cfg->mqrx_supported) { + count = IWM_RX_MQ_RING_COUNT; + descsz = sizeof(uint64_t); + } else { + count = IWM_RX_LEGACY_RING_COUNT; + descsz = sizeof(uint32_t); + } /* Allocate RX descriptors (256-byte aligned). */ - size = IWM_RX_RING_COUNT * sizeof(uint32_t); - error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256); + size = count * descsz; + error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->free_desc_dma, size, + 256); if (error != 0) { device_printf(sc->sc_dev, "could not allocate RX ring DMA memory\n"); goto fail; } - ring->desc = ring->desc_dma.vaddr; + ring->desc = ring->free_desc_dma.vaddr; /* Allocate RX status area (16-byte aligned). */ error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma, @@ -953,6 +959,17 @@ iwm_alloc_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) } ring->stat = ring->stat_dma.vaddr; + if (sc->cfg->mqrx_supported) { + size = count * sizeof(uint32_t); + error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->used_desc_dma, + size, 256); + if (error != 0) { + device_printf(sc->sc_dev, + "could not allocate RX ring DMA memory\n"); + goto fail; + } + } + /* Create RX buffer DMA tag. */ error = bus_dma_tag_create(sc->sc_dmat, 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, @@ -972,10 +989,11 @@ iwm_alloc_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) __func__, error); goto fail; } + /* * Allocate and map RX buffers. */ - for (i = 0; i < IWM_RX_RING_COUNT; i++) { + for (i = 0; i < count; i++) { struct iwm_rx_data *data = &ring->data[i]; error = bus_dmamap_create(ring->data_dmat, 0, &data->map); if (error != 0) { @@ -1013,12 +1031,16 @@ iwm_reset_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) static void iwm_free_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) { - int i; + int count, i; - iwm_dma_contig_free(&ring->desc_dma); + iwm_dma_contig_free(&ring->free_desc_dma); iwm_dma_contig_free(&ring->stat_dma); + iwm_dma_contig_free(&ring->used_desc_dma); + + count = sc->cfg->mqrx_supported ? IWM_RX_MQ_RING_COUNT : + IWM_RX_LEGACY_RING_COUNT; - for (i = 0; i < IWM_RX_RING_COUNT; i++) { + for (i = 0; i < count; i++) { struct iwm_rx_data *data = &ring->data[i]; if (data->m != NULL) { @@ -1315,12 +1337,14 @@ iwm_stop_device(struct iwm_softc *sc) /* Stop the device, and put it in low power state */ iwm_apm_stop(sc); - /* Upon stop, the APM issues an interrupt if HW RF kill is set. - * Clean again the interrupt here + /* stop and reset the on-board processor */ + IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET); + DELAY(5000); + + /* + * Upon stop, the APM issues an interrupt if HW RF kill is set. */ iwm_disable_interrupts(sc); - /* stop and reset the on-board processor */ - 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 @@ -1328,6 +1352,8 @@ iwm_stop_device(struct iwm_softc *sc) */ iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); + + iwm_prepare_card_hw(sc); } /* iwlwifi: mvm/ops.c */ @@ -1356,7 +1382,15 @@ iwm_mvm_nic_config(struct iwm_softc *sc) reg_val |= radio_cfg_step << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; - IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG, reg_val); + IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG, + IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | + IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | + IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | + IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | + IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | + IWM_CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + IWM_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI | + reg_val); IWM_DPRINTF(sc, IWM_DEBUG_RESET, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, @@ -1375,12 +1409,61 @@ iwm_mvm_nic_config(struct iwm_softc *sc) } static int -iwm_nic_rx_init(struct iwm_softc *sc) +iwm_nic_rx_mq_init(struct iwm_softc *sc) +{ + int enabled; + + if (!iwm_nic_lock(sc)) + return EBUSY; + + /* Stop RX DMA. */ + iwm_write_prph(sc, IWM_RFH_RXF_DMA_CFG, 0); + /* Disable RX used and free queue operation. */ + iwm_write_prph(sc, IWM_RFH_RXF_RXQ_ACTIVE, 0); + + iwm_write_prph64(sc, IWM_RFH_Q0_FRBDCB_BA_LSB, + sc->rxq.free_desc_dma.paddr); + iwm_write_prph64(sc, IWM_RFH_Q0_URBDCB_BA_LSB, + sc->rxq.used_desc_dma.paddr); + iwm_write_prph64(sc, IWM_RFH_Q0_URBD_STTS_WPTR_LSB, + sc->rxq.stat_dma.paddr); + iwm_write_prph(sc, IWM_RFH_Q0_FRBDCB_WIDX, 0); + iwm_write_prph(sc, IWM_RFH_Q0_FRBDCB_RIDX, 0); + iwm_write_prph(sc, IWM_RFH_Q0_URBDCB_WIDX, 0); + + /* We configure only queue 0 for now. */ + enabled = ((1 << 0) << 16) | (1 << 0); + + /* Enable RX DMA, 4KB buffer size. */ + iwm_write_prph(sc, IWM_RFH_RXF_DMA_CFG, + IWM_RFH_DMA_EN_ENABLE_VAL | + IWM_RFH_RXF_DMA_RB_SIZE_4K | + IWM_RFH_RXF_DMA_MIN_RB_4_8 | + IWM_RFH_RXF_DMA_DROP_TOO_LARGE_MASK | + IWM_RFH_RXF_DMA_RBDCB_SIZE_512); + + /* Enable RX DMA snooping. */ + iwm_write_prph(sc, IWM_RFH_GEN_CFG, + IWM_RFH_GEN_CFG_RFH_DMA_SNOOP | + IWM_RFH_GEN_CFG_SERVICE_DMA_SNOOP | + (sc->cfg->integrated ? IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_64 : + IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_128)); + + /* Enable the configured queue(s). */ + iwm_write_prph(sc, IWM_RFH_RXF_RXQ_ACTIVE, enabled); + + iwm_nic_unlock(sc); + + IWM_WRITE_1(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_TIMEOUT_DEF); + + IWM_WRITE(sc, IWM_RFH_Q0_FRBDCB_WIDX_TRG, 8); + + return (0); +} + +static int +iwm_nic_rx_legacy_init(struct iwm_softc *sc) { - /* - * Initialize RX ring. This is from the iwn driver. - */ - memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat)); /* Stop Rx DMA */ iwm_pcie_rx_stop(sc); @@ -1396,7 +1479,8 @@ iwm_nic_rx_init(struct iwm_softc *sc) /* Set physical address of RX ring (256-byte aligned). */ IWM_WRITE(sc, - IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG, sc->rxq.desc_dma.paddr >> 8); + IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG, + sc->rxq.free_desc_dma.paddr >> 8); /* Set physical address of RX status (16-byte aligned). */ IWM_WRITE(sc, @@ -1425,19 +1509,22 @@ iwm_nic_rx_init(struct iwm_softc *sc) if (sc->cfg->host_interrupt_operation_mode) IWM_SETBITS(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_OPER_MODE); - /* - * 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) - */ - IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, 8); - iwm_nic_unlock(sc); + IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, 8); + return 0; } +static int +iwm_nic_rx_init(struct iwm_softc *sc) +{ + if (sc->cfg->mqrx_supported) + return iwm_nic_rx_mq_init(sc); + else + return iwm_nic_rx_legacy_init(sc); +} + static int iwm_nic_tx_init(struct iwm_softc *sc) { @@ -1466,7 +1553,9 @@ iwm_nic_tx_init(struct iwm_softc *sc) (unsigned long) (txq->desc_dma.paddr >> 8)); } - iwm_write_prph(sc, IWM_SCD_GP_CTRL, IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE); + iwm_set_bits_prph(sc, IWM_SCD_GP_CTRL, + IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE | + IWM_SCD_GP_CTRL_ENABLE_31_QUEUES); iwm_nic_unlock(sc); @@ -1503,25 +1592,31 @@ iwm_nic_init(struct iwm_softc *sc) int iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo) { + int qmsk; + + qmsk = 1 << qid; + if (!iwm_nic_lock(sc)) { - device_printf(sc->sc_dev, - "%s: cannot enable txq %d\n", - __func__, - qid); + device_printf(sc->sc_dev, "%s: cannot enable txq %d\n", + __func__, qid); return EBUSY; } IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0); if (qid == IWM_MVM_CMD_QUEUE) { - /* unactivate before configuration */ + /* Disable the scheduler. */ + iwm_write_prph(sc, IWM_SCD_EN_CTRL, 0); + + /* Stop the TX queue prior to 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)); + (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); iwm_nic_unlock(sc); - iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid)); + /* Disable aggregations for this queue. */ + iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, qmsk); if (!iwm_nic_lock(sc)) { device_printf(sc->sc_dev, @@ -1531,7 +1626,8 @@ iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo) iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0); iwm_nic_unlock(sc); - iwm_write_mem32(sc, sc->scd_base_addr + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0); + iwm_write_mem32(sc, + sc->scd_base_addr + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0); /* Set scheduler window size and frame limit. */ iwm_write_mem32(sc, sc->scd_base_addr + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) + @@ -1551,6 +1647,9 @@ iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo) (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) | (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) | IWM_SCD_QUEUE_STTS_REG_MSK); + + /* Enable the scheduler for this queue. */ + iwm_write_prph(sc, IWM_SCD_EN_CTRL, qmsk); } else { struct iwm_scd_txq_cfg_cmd cmd; int error; @@ -1577,9 +1676,6 @@ iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo) return EBUSY; } - 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", @@ -1651,7 +1747,7 @@ iwm_trans_pcie_fw_alive(struct iwm_softc *sc, uint32_t scd_base_addr) iwm_nic_unlock(sc); /* Enable L1-Active */ - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family < IWM_DEVICE_FAMILY_8000) { iwm_clear_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG, IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } @@ -2069,7 +2165,7 @@ static int iwm_get_sku(const struct iwm_softc *sc, const uint16_t *nvm_sw, const uint16_t *phy_sku) { - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->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)); @@ -2078,7 +2174,7 @@ iwm_get_sku(const struct iwm_softc *sc, const uint16_t *nvm_sw, static int iwm_get_nvm_version(const struct iwm_softc *sc, const uint16_t *nvm_sw) { - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->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 + @@ -2089,7 +2185,7 @@ static int iwm_get_radio_cfg(const struct iwm_softc *sc, const uint16_t *nvm_sw, const uint16_t *phy_sku) { - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->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)); @@ -2100,7 +2196,7 @@ iwm_get_n_hw_addrs(const struct iwm_softc *sc, const uint16_t *nvm_sw) { int n_hw_addr; - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) + if (sc->cfg->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)); @@ -2112,7 +2208,7 @@ static void iwm_set_radio_cfg(const struct iwm_softc *sc, struct iwm_nvm_data *data, uint32_t radio_cfg) { - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->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); @@ -2138,7 +2234,7 @@ iwm_set_hw_address(struct iwm_softc *sc, struct iwm_nvm_data *data, iwm_set_hw_address_from_csr(sc, data); } else #endif - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family < IWM_DEVICE_FAMILY_8000) { const uint8_t *hw_addr = (const uint8_t *)(nvm_hw + IWM_HW_ADDR); /* The byte order is little endian 16 bit, meaning 214365 */ @@ -2170,7 +2266,7 @@ iwm_parse_nvm_data(struct iwm_softc *sc, uint32_t sku, radio_cfg; uint16_t lar_config; - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family < IWM_DEVICE_FAMILY_8000) { data = malloc(sizeof(*data) + IWM_NUM_CHANNELS * sizeof(uint16_t), M_DEVBUF, M_NOWAIT | M_ZERO); @@ -2194,7 +2290,8 @@ iwm_parse_nvm_data(struct iwm_softc *sc, data->n_hw_addrs = iwm_get_n_hw_addrs(sc, nvm_sw); - if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_8000) { + /* TODO: use IWL_NVM_EXT */ uint16_t lar_offset = data->nvm_version < 0xE39 ? IWM_NVM_LAR_OFFSET_8000_OLD : IWM_NVM_LAR_OFFSET_8000; @@ -2242,7 +2339,7 @@ iwm_parse_nvm_sections(struct iwm_softc *sc, struct iwm_nvm_section *sections) "Can't parse empty OTP/NVM sections\n"); return NULL; } - } else if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) { + } else if (sc->cfg->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) { @@ -2672,7 +2769,7 @@ iwm_start_fw(struct iwm_softc *sc, const struct iwm_fw_img *fw) IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL); /* Load the given image to the HW */ - if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_8000) ret = iwm_pcie_load_given_ucode_8000(sc, fw); else ret = iwm_pcie_load_given_ucode(sc, fw); @@ -2823,7 +2920,7 @@ iwm_mvm_load_ucode_wait_alive(struct iwm_softc *sc, IWM_MVM_UCODE_ALIVE_TIMEOUT); IWM_LOCK(sc); if (error) { - if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_8000) { uint32_t a = 0x5a5a5a5a, b = 0x5a5a5a5a; if (iwm_nic_lock(sc)) { a = iwm_read_prph(sc, IWM_SB_CPU_1_STATUS); @@ -2914,6 +3011,15 @@ iwm_run_init_mvm_ucode(struct iwm_softc *sc, int justnvm) goto error; } + if (sc->cfg->device_family < IWM_DEVICE_FAMILY_8000) { + ret = iwm_send_bt_init_conf(sc); + if (ret) { + device_printf(sc->sc_dev, + "failed to send bt coex configuration: %d\n", ret); + goto error; + } + } + if (justnvm) { /* Read nvm */ ret = iwm_nvm_init(sc); @@ -2925,13 +3031,6 @@ iwm_run_init_mvm_ucode(struct iwm_softc *sc, int justnvm) goto error; } - ret = iwm_send_bt_init_conf(sc); - if (ret) { - device_printf(sc->sc_dev, - "failed to send bt coex configuration: %d\n", ret); - goto error; - } - /* Send TX valid antennas before triggering calibrations */ ret = iwm_send_tx_ant_cfg(sc, iwm_mvm_get_valid_tx_ant(sc)); if (ret) { @@ -3025,46 +3124,17 @@ iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx) /* Update RX descriptor. */ 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, + if (sc->cfg->mqrx_supported) + ((uint64_t *)ring->desc)[idx] = + htole64(seg.ds_addr | (idx + 1)); + else + ((uint32_t *)ring->desc)[idx] = htole32(seg.ds_addr >> 8); + bus_dmamap_sync(ring->free_desc_dma.tag, ring->free_desc_dma.map, BUS_DMASYNC_PREWRITE); return 0; } -/* iwlwifi: mvm/rx.c */ -/* - * iwm_mvm_get_signal_strength - use new rx PHY INFO API - * values are reported by the fw as positive values - need to negate - * to obtain their dBM. Account for missing antennas by replacing 0 - * values by -256dBm: practically 0 power and a non-feasible 8 bit value. - */ -static int -iwm_mvm_get_signal_strength(struct iwm_softc *sc, struct iwm_rx_phy_info *phy_info) -{ - int energy_a, energy_b, energy_c, max_energy; - uint32_t val; - - val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_ENERGY_ANT_ABC_IDX]); - energy_a = (val & IWM_RX_INFO_ENERGY_ANT_A_MSK) >> - IWM_RX_INFO_ENERGY_ANT_A_POS; - energy_a = energy_a ? -energy_a : -256; - energy_b = (val & IWM_RX_INFO_ENERGY_ANT_B_MSK) >> - IWM_RX_INFO_ENERGY_ANT_B_POS; - energy_b = energy_b ? -energy_b : -256; - energy_c = (val & IWM_RX_INFO_ENERGY_ANT_C_MSK) >> - IWM_RX_INFO_ENERGY_ANT_C_POS; - energy_c = energy_c ? -energy_c : -256; - max_energy = MAX(energy_a, energy_b); - max_energy = MAX(max_energy, energy_c); - - IWM_DPRINTF(sc, IWM_DEBUG_RECV, - "energy In A %d B %d C %d , and max %d\n", - energy_a, energy_b, energy_c, max_energy); - - return max_energy; -} - static void iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt) { @@ -3118,19 +3188,65 @@ iwm_mvm_handle_rx_statistics(struct iwm_softc *sc, struct iwm_rx_packet *pkt) sc->sc_noise = iwm_get_noise(sc, &stats->rx.general); } +/* iwlwifi: mvm/rx.c */ +/* + * iwm_mvm_get_signal_strength - use new rx PHY INFO API + * values are reported by the fw as positive values - need to negate + * to obtain their dBM. Account for missing antennas by replacing 0 + * values by -256dBm: practically 0 power and a non-feasible 8 bit value. + */ +static int +iwm_mvm_rx_get_signal_strength(struct iwm_softc *sc, + struct iwm_rx_phy_info *phy_info) +{ + int energy_a, energy_b, energy_c, max_energy; + uint32_t val; + + val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_ENERGY_ANT_ABC_IDX]); + energy_a = (val & IWM_RX_INFO_ENERGY_ANT_A_MSK) >> + IWM_RX_INFO_ENERGY_ANT_A_POS; + energy_a = energy_a ? -energy_a : -256; + energy_b = (val & IWM_RX_INFO_ENERGY_ANT_B_MSK) >> + IWM_RX_INFO_ENERGY_ANT_B_POS; + energy_b = energy_b ? -energy_b : -256; + energy_c = (val & IWM_RX_INFO_ENERGY_ANT_C_MSK) >> + IWM_RX_INFO_ENERGY_ANT_C_POS; + energy_c = energy_c ? -energy_c : -256; + max_energy = MAX(energy_a, energy_b); + max_energy = MAX(max_energy, energy_c); + + IWM_DPRINTF(sc, IWM_DEBUG_RECV, + "energy In A %d B %d C %d , and max %d\n", + energy_a, energy_b, energy_c, max_energy); + + return max_energy; +} + +static int +iwm_mvm_rxmq_get_signal_strength(struct iwm_softc *sc, + struct iwm_rx_mpdu_desc *desc) +{ + int energy_a, energy_b; + + energy_a = desc->v1.energy_a; + energy_b = desc->v1.energy_b; + energy_a = energy_a ? -energy_a : -256; + energy_b = energy_b ? -energy_b : -256; + return MAX(energy_a, energy_b); +} + /* * iwm_mvm_rx_rx_mpdu - IWM_REPLY_RX_MPDU_CMD handler * * Handles the actual data of the Rx packet from the fw */ -static boolean_t +static bool iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, - boolean_t stolen) + bool stolen) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_frame *wh; - struct ieee80211_node *ni; struct ieee80211_rx_stats rxs; struct iwm_rx_phy_info *phy_info; struct iwm_rx_mpdu_res_start *rx_res; @@ -3149,17 +3265,17 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, device_printf(sc->sc_dev, "dsp size out of range [0,20]: %d\n", phy_info->cfg_phy_cnt); - goto fail; + return false; } if (!(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_CRC_OK) || !(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_OVERRUN_OK)) { IWM_DPRINTF(sc, IWM_DEBUG_RECV, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); - goto fail; + return false; } - rssi = iwm_mvm_get_signal_strength(sc, phy_info); + rssi = iwm_mvm_rx_get_signal_strength(sc, phy_info); /* Map it to relative value */ rssi = rssi - sc->sc_noise; @@ -3168,7 +3284,7 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, if (!stolen && iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0) { device_printf(sc->sc_dev, "%s: unable to add more buffers\n", __func__); - goto fail; + return false; } m->m_data = pkt->data + sizeof(*rx_res); @@ -3177,8 +3293,6 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, IWM_DPRINTF(sc, IWM_DEBUG_RECV, "%s: rssi=%d, noise=%d\n", __func__, rssi, sc->sc_noise); - ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); - IWM_DPRINTF(sc, IWM_DEBUG_RECV, "%s: phy_info: channel=%d, flags=0x%08x\n", __func__, @@ -3201,11 +3315,8 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, /* rssi is in 1/2db units */ rxs.c_rssi = rssi * 2; rxs.c_nf = sc->sc_noise; - if (ieee80211_add_rx_params(m, &rxs) == 0) { - if (ni) - ieee80211_free_node(ni); - goto fail; - } + if (ieee80211_add_rx_params(m, &rxs) == 0) + return false; if (ieee80211_radiotap_active_vap(vap)) { struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap; @@ -3239,6 +3350,139 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, } } + return true; +} + +static bool +iwm_mvm_rx_mpdu_mq(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, + bool stolen) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211_frame *wh; + struct ieee80211_rx_stats rxs; + struct iwm_rx_mpdu_desc *desc; + struct iwm_rx_packet *pkt; + int rssi; + uint32_t hdrlen, len, rate_n_flags; + uint16_t phy_info; + uint8_t channel; + + pkt = mtodo(m, offset); + desc = (void *)pkt->data; + + if (!(desc->status & htole16(IWM_RX_MPDU_RES_STATUS_CRC_OK)) || + !(desc->status & htole16(IWM_RX_MPDU_RES_STATUS_OVERRUN_OK))) { + IWM_DPRINTF(sc, IWM_DEBUG_RECV, + "Bad CRC or FIFO: 0x%08X.\n", desc->status); + return false; + } + + channel = desc->v1.channel; + len = le16toh(desc->mpdu_len); + phy_info = le16toh(desc->phy_info); + rate_n_flags = desc->v1.rate_n_flags; + + wh = mtodo(m, sizeof(*desc)); + m->m_data = pkt->data + sizeof(*desc); + m->m_pkthdr.len = m->m_len = len; + m->m_len = len; + + /* Account for padding following the frame header. */ + if ((desc->mac_flags2 & IWM_RX_MPDU_MFLG2_PAD)) { + hdrlen = ieee80211_anyhdrsize(wh); + memmove(mtodo(m, 2), mtodo(m, 0), hdrlen); + m->m_data = mtodo(m, 2); + wh = mtod(m, struct ieee80211_frame *); + } + + /* Map it to relative value */ + rssi = iwm_mvm_rxmq_get_signal_strength(sc, desc); + rssi = rssi - sc->sc_noise; + + /* replenish ring for the buffer we're going to feed to the sharks */ + if (!stolen && iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0) { + device_printf(sc->sc_dev, "%s: unable to add more buffers\n", + __func__); + return false; + } + + IWM_DPRINTF(sc, IWM_DEBUG_RECV, + "%s: rssi=%d, noise=%d\n", __func__, rssi, sc->sc_noise); + + /* + * Populate an RX state struct with the provided information. + */ + bzero(&rxs, sizeof(rxs)); + rxs.r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ; + rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI; + rxs.c_ieee = channel; + rxs.c_freq = ieee80211_ieee2mhz(rxs.c_ieee, + channel <= 14 ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ); + + /* rssi is in 1/2db units */ + rxs.c_rssi = rssi * 2; + rxs.c_nf = sc->sc_noise; + if (ieee80211_add_rx_params(m, &rxs) == 0) + return false; + + if (ieee80211_radiotap_active_vap(vap)) { + struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap; + + tap->wr_flags = 0; + if ((phy_info & IWM_RX_MPDU_PHY_SHORT_PREAMBLE) != 0) + tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + tap->wr_chan_freq = htole16(rxs.c_freq); + /* XXX only if ic->ic_curchan->ic_ieee == rxs.c_ieee */ + tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); + tap->wr_dbm_antsignal = (int8_t)rssi; + tap->wr_dbm_antnoise = (int8_t)sc->sc_noise; + tap->wr_tsft = desc->v1.gp2_on_air_rise; + switch ((rate_n_flags & 0xff)) { + /* CCK rates. */ + case 10: tap->wr_rate = 2; break; + case 20: tap->wr_rate = 4; break; + case 55: tap->wr_rate = 11; break; + case 110: tap->wr_rate = 22; break; + /* OFDM rates. */ + case 0xd: tap->wr_rate = 12; break; + case 0xf: tap->wr_rate = 18; break; + case 0x5: tap->wr_rate = 24; break; + case 0x7: tap->wr_rate = 36; break; + case 0x9: tap->wr_rate = 48; break; + case 0xb: tap->wr_rate = 72; break; + case 0x1: tap->wr_rate = 96; break; + case 0x3: tap->wr_rate = 108; break; + /* Unknown rate: should not happen. */ + default: tap->wr_rate = 0; + } + } + + return true; +} + +static bool +iwm_mvm_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, + bool stolen) +{ + struct ieee80211com *ic; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + bool ret; + + ic = &sc->sc_ic; + + ret = sc->cfg->mqrx_supported ? + iwm_mvm_rx_mpdu_mq(sc, m, offset, stolen) : + iwm_mvm_rx_rx_mpdu(sc, m, offset, stolen); + if (!ret) { + counter_u64_add(ic->ic_ierrors, 1); + return (ret); + } + + wh = mtod(m, struct ieee80211_frame *); + ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); + IWM_UNLOCK(sc); if (ni != NULL) { IWM_DPRINTF(sc, IWM_DEBUG_RECV, "input m %p\n", m); @@ -3250,11 +3494,7 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, } IWM_LOCK(sc); - return TRUE; - -fail: - counter_u64_add(ic->ic_ierrors, 1); - return FALSE; + return true; } static int @@ -3338,13 +3578,20 @@ static void iwm_mvm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt) { struct iwm_cmd_header *cmd_hdr = &pkt->hdr; - int idx = cmd_hdr->idx; - int qid = cmd_hdr->qid; - struct iwm_tx_ring *ring = &sc->txq[qid]; - struct iwm_tx_data *txd = &ring->data[idx]; - struct iwm_node *in = txd->in; - struct mbuf *m = txd->m; - int status; + struct iwm_tx_ring *ring; + struct iwm_tx_data *txd; + struct iwm_node *in; + struct mbuf *m; + int idx, qid, qmsk, status; + + idx = cmd_hdr->idx; + qid = cmd_hdr->qid; + qmsk = 1 << qid; + + ring = &sc->txq[qid]; + txd = &ring->data[idx]; + in = txd->in; + m = txd->m; KASSERT(txd->done == 0, ("txd not done")); KASSERT(txd->in != NULL, ("txd without node")); @@ -3366,11 +3613,10 @@ iwm_mvm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt) ieee80211_tx_complete(&in->in_ni, m, status); - if (--ring->queued < IWM_TX_RING_LOMARK) { - sc->qfullmsk &= ~(1 << ring->qid); - if (sc->qfullmsk == 0) { + if (--ring->queued < IWM_TX_RING_LOMARK && (sc->qfullmsk & qmsk) != 0) { + sc->qfullmsk &= ~qmsk; + if (sc->qfullmsk == 0) iwm_start(sc); - } } } @@ -3531,7 +3777,10 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in, ); /* XXX TODO: hard-coded TX antenna? */ - rate_flags = 1 << IWM_RATE_MCS_ANT_POS; + if (sc->cfg->device_family == IWM_DEVICE_FAMILY_9000) + rate_flags = IWM_RATE_MCS_ANT_B_MSK; + else + rate_flags = IWM_RATE_MCS_ANT_A_MSK; if (IWM_RIDX_IS_CCK(ridx)) rate_flags |= IWM_RATE_MCS_CCK_MSK; tx->rate_n_flags = htole32(rate_flags | rinfo->plcp); @@ -3568,7 +3817,6 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac) tid = 0; ring = &sc->txq[ac]; desc = &ring->desc[ring->cur]; - memset(desc, 0, sizeof(*desc)); data = &ring->data[ring->cur]; /* Fill out iwm_tx_cmd to send to the firmware */ @@ -3607,25 +3855,19 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac) ieee80211_radiotap_tx(vap, m); } - - totlen = m->m_pkthdr.len; - flags = 0; + totlen = m->m_pkthdr.len; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= IWM_TX_CMD_FLG_ACK; } - if (type == IEEE80211_FC0_TYPE_DATA - && (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) - && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (type == IEEE80211_FC0_TYPE_DATA && + totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= IWM_TX_CMD_FLG_PROT_REQUIRE; } - if (IEEE80211_IS_MULTICAST(wh->i_addr1) || - type != IEEE80211_FC0_TYPE_DATA) - tx->sta_id = sc->sc_aux_sta.sta_id; - else - tx->sta_id = IWM_STATION_ID; + tx->sta_id = IWM_STATION_ID; if (type == IEEE80211_FC0_TYPE_MGT) { uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; @@ -3645,12 +3887,12 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac) if (hdrlen & 3) { /* First segment length must be a multiple of 4. */ flags |= IWM_TX_CMD_FLG_MH_PAD; + tx->offload_assist |= htole16(1 << IWM_TX_CMD_OFFLD_PAD); pad = 4 - (hdrlen & 3); - } else + } else { + tx->offload_assist = 0; pad = 0; - - tx->driver_txop = 0; - tx->next_frame_len = 0; + } tx->len = htole16(totlen); tx->tid_tspec = tid; @@ -3661,7 +3903,7 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac) tx->dram_msb_ptr = iwm_get_dma_hi_addr(data->scratch_paddr); /* Copy 802.11 header in TX command. */ - memcpy(((uint8_t *)tx) + sizeof(*tx), wh, hdrlen); + memcpy((uint8_t *)tx + sizeof(*tx), wh, hdrlen); flags |= IWM_TX_CMD_FLG_BT_DIS | IWM_TX_CMD_FLG_SEQ_CTL; @@ -3715,23 +3957,24 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac) ); /* Fill TX descriptor. */ + memset(desc, 0, sizeof(*desc)); desc->num_tbs = 2 + nsegs; desc->tbs[0].lo = htole32(data->cmd_paddr); - desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) | - (TB0_SIZE << 4); + desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr) | + (TB0_SIZE << 4)); desc->tbs[1].lo = htole32(data->cmd_paddr + TB0_SIZE); - desc->tbs[1].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) | - ((sizeof(struct iwm_cmd_header) + sizeof(*tx) - + hdrlen + pad - TB0_SIZE) << 4); + desc->tbs[1].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr) | + ((sizeof(struct iwm_cmd_header) + sizeof(*tx) + + hdrlen + pad - TB0_SIZE) << 4)); /* Other DMA segments are for data payload. */ for (i = 0; i < nsegs; i++) { seg = &segs[i]; - desc->tbs[i+2].lo = htole32(seg->ds_addr); - desc->tbs[i+2].hi_n_len = \ - htole16(iwm_get_dma_hi_addr(seg->ds_addr)) - | ((seg->ds_len) << 4); + desc->tbs[i + 2].lo = htole32(seg->ds_addr); + desc->tbs[i + 2].hi_n_len = + htole16(iwm_get_dma_hi_addr(seg->ds_addr)) | + (seg->ds_len << 4); } bus_dmamap_sync(ring->data_dmat, data->map, @@ -4444,8 +4687,7 @@ static boolean_t iwm_mvm_is_lar_supported(struct iwm_softc *sc) { boolean_t nvm_lar = sc->nvm_data->lar_enabled; - boolean_t tlv_lar = fw_has_capa(&sc->sc_fw.ucode_capa, - IWM_UCODE_TLV_CAPA_LAR_SUPPORT); + boolean_t tlv_lar = iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_LAR_SUPPORT); if (iwm_lar_disable) return FALSE; @@ -4454,7 +4696,7 @@ iwm_mvm_is_lar_supported(struct iwm_softc *sc) * Enable LAR only if it is supported by the FW (TLV) && * enabled in the NVM */ - if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_8000) return nvm_lar && tlv_lar; else return tlv_lar; @@ -4463,10 +4705,8 @@ iwm_mvm_is_lar_supported(struct iwm_softc *sc) static boolean_t iwm_mvm_is_wifi_mcc_supported(struct iwm_softc *sc) { - return fw_has_api(&sc->sc_fw.ucode_capa, - IWM_UCODE_TLV_API_WIFI_MCC_UPDATE) || - fw_has_capa(&sc->sc_fw.ucode_capa, - IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC); + return iwm_fw_has_api(sc, IWM_UCODE_TLV_API_WIFI_MCC_UPDATE) || + iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC); } static int @@ -4486,8 +4726,7 @@ iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2) int n_channels; uint16_t mcc; #endif - int resp_v2 = fw_has_capa(&sc->sc_fw.ucode_capa, - IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2); + int resp_v2 = iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2); if (!iwm_mvm_is_lar_supported(sc)) { IWM_DPRINTF(sc, IWM_DEBUG_LAR, "%s: no LAR support\n", @@ -4648,7 +4887,7 @@ iwm_init_hw(struct iwm_softc *sc) if ((error = iwm_send_update_mcc_cmd(sc, "ZZ")) != 0) goto error; - if (fw_has_capa(&sc->sc_fw.ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) { + if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) { if ((error = iwm_mvm_config_umac_scan(sc)) != 0) goto error; } @@ -5148,7 +5387,7 @@ iwm_handle_rxb(struct iwm_softc *sc, struct mbuf *m) nextpkt->hdr.idx == 0) || (nextpkt->len_n_flags == htole32(IWM_FH_RSCSR_FRAME_INVALID))) { - if (iwm_mvm_rx_rx_mpdu(sc, m, offset, stolen)) { + if (iwm_mvm_rx_mpdu(sc, m, offset, stolen)) { stolen = FALSE; /* Make sure we abort the loop */ nextoff = maxoff; @@ -5159,14 +5398,14 @@ iwm_handle_rxb(struct iwm_softc *sc, struct mbuf *m) /* * Use m_copym instead of m_split, because that * makes it easier to keep a valid rx buffer in - * the ring, when iwm_mvm_rx_rx_mpdu() fails. + * the ring, when iwm_mvm_rx_mpdu() fails. * * We need to start m_copym() at offset 0, to get the * M_PKTHDR flag preserved. */ m1 = m_copym(m, 0, M_COPYALL, M_NOWAIT); if (m1) { - if (iwm_mvm_rx_rx_mpdu(sc, m1, offset, stolen)) + if (iwm_mvm_rx_mpdu(sc, m1, offset, stolen)) stolen = TRUE; else m_freem(m1); @@ -5415,11 +5654,21 @@ iwm_handle_rxb(struct iwm_softc *sc, struct mbuf *m) static void iwm_notif_intr(struct iwm_softc *sc) { + int count; + uint32_t wreg; uint16_t hw; bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map, BUS_DMASYNC_POSTREAD); + if (sc->cfg->mqrx_supported) { + count = IWM_RX_MQ_RING_COUNT; + wreg = IWM_RFH_Q0_FRBDCB_WIDX_TRG; + } else { + count = IWM_RX_LEGACY_RING_COUNT; + wreg = IWM_FH_RSCSR_CHNL0_WPTR; + } + hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff; /* @@ -5436,7 +5685,7 @@ iwm_notif_intr(struct iwm_softc *sc) "%s: hw = %d cur = %d\n", __func__, hw, ring->cur); iwm_handle_rxb(sc, data->m); - ring->cur = (ring->cur + 1) % IWM_RX_RING_COUNT; + ring->cur = (ring->cur + 1) % count; } /* @@ -5445,8 +5694,8 @@ iwm_notif_intr(struct iwm_softc *sc) * Seems like the hardware gets upset unless we align * the write by 8?? */ - hw = (hw == 0) ? IWM_RX_RING_COUNT - 1 : hw - 1; - IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, rounddown2(hw, 8)); + hw = (hw == 0) ? count - 1 : hw - 1; + IWM_WRITE(sc, wreg, rounddown2(hw, 8)); } static void @@ -5621,6 +5870,9 @@ iwm_intr(void *arg) #define PCI_PRODUCT_INTEL_WL_8260_1 0x24f3 #define PCI_PRODUCT_INTEL_WL_8260_2 0x24f4 #define PCI_PRODUCT_INTEL_WL_8265_1 0x24fd +#define PCI_PRODUCT_INTEL_WL_9560_1 0x9df0 +#define PCI_PRODUCT_INTEL_WL_9560_2 0xa370 +#define PCI_PRODUCT_INTEL_WL_9260_1 0x2526 static const struct iwm_devices { uint16_t device; @@ -5638,6 +5890,9 @@ static const struct iwm_devices { { PCI_PRODUCT_INTEL_WL_8260_1, &iwm8260_cfg }, { PCI_PRODUCT_INTEL_WL_8260_2, &iwm8260_cfg }, { PCI_PRODUCT_INTEL_WL_8265_1, &iwm8265_cfg }, + { PCI_PRODUCT_INTEL_WL_9560_1, &iwm9560_cfg }, + { PCI_PRODUCT_INTEL_WL_9560_2, &iwm9560_cfg }, + { PCI_PRODUCT_INTEL_WL_9260_1, &iwm9260_cfg }, }; static int @@ -5749,8 +6004,6 @@ iwm_pci_detach(device_t dev) rman_get_rid(sc->sc_mem), sc->sc_mem); } - - static int iwm_attach(device_t dev) { @@ -5761,12 +6014,17 @@ iwm_attach(device_t dev) sc->sc_dev = dev; sc->sc_attached = 1; + sc->sc_debug = (sc->sc_debug | IWM_DEBUG_ANY); IWM_LOCK_INIT(sc); mbufq_init(&sc->sc_snd, ifqmaxlen); callout_init_mtx(&sc->sc_watchdog_to, &sc->sc_mtx, 0); callout_init_mtx(&sc->sc_led_blink_to, &sc->sc_mtx, 0); TASK_INIT(&sc->sc_es_task, 0, iwm_endscan_cb, sc); + error = iwm_dev_check(dev); + if (error != 0) + goto fail; + sc->sc_notif_wait = iwm_notification_wait_init(sc); if (sc->sc_notif_wait == NULL) { device_printf(dev, "failed to init notification wait struct\n"); @@ -5792,11 +6050,6 @@ iwm_attach(device_t dev) sc->sc_wantresp = -1; - /* Match device id */ - error = iwm_dev_check(dev); - if (error != 0) - goto fail; - 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 @@ -5804,7 +6057,7 @@ iwm_attach(device_t dev) * "dash" value). To keep hw_rev backwards compatible - we'll store it * in the old format. */ - if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_8000) { int ret; uint32_t hw_step; @@ -6185,7 +6438,7 @@ iwm_scan_start(struct ieee80211com *ic) device_printf(sc->sc_dev, "%s: Previous scan not completed yet\n", __func__); } - if (fw_has_capa(&sc->sc_fw.ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) + if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) error = iwm_mvm_umac_scan(sc); else error = iwm_mvm_lmac_scan(sc); diff --git a/sys/dev/iwm/if_iwm_9000.c b/sys/dev/iwm/if_iwm_9000.c new file mode 100644 index 000000000000..fe7898c5b483 --- /dev/null +++ b/sys/dev/iwm/if_iwm_9000.c @@ -0,0 +1,97 @@ +/*- + * Based on BSD-licensed source modules in the Linux iwlwifi driver, + * which were used as the reference documentation for this implementation. + * + ****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" +#include "opt_iwm.h" + +#include + +#include "if_iwm_config.h" + +#define IWM9000_FW "iwm9000fw" + +#define IWM_NVM_HW_SECTION_NUM_FAMILY_9000 10 + +#define IWM_DEVICE_9000_COMMON \ + .device_family = IWM_DEVICE_FAMILY_9000, \ + .eeprom_size = IWM_OTP_LOW_IMAGE_SIZE_FAMILY_9000, \ + .nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_9000 + +const struct iwm_cfg iwm9560_cfg = { + .name = "Intel(R) Dual Band Wireless AC 9560", + .fw_name = IWM9000_FW, + IWM_DEVICE_9000_COMMON, + .host_interrupt_operation_mode = 0, + .mqrx_supported = 1, + .integrated = 1, +}; diff --git a/sys/dev/iwm/if_iwm_9260.c b/sys/dev/iwm/if_iwm_9260.c new file mode 100644 index 000000000000..a92ba9ebbe35 --- /dev/null +++ b/sys/dev/iwm/if_iwm_9260.c @@ -0,0 +1,96 @@ +/*- + * Based on BSD-licensed source modules in the Linux iwlwifi driver, + * which were used as the reference documentation for this implementation. + * + ****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" +#include "opt_iwm.h" + +#include + +#include "if_iwm_config.h" + +#define IWM9260_FW "iwm9260fw" + +#define IWM_NVM_HW_SECTION_NUM_FAMILY_9260 10 + +#define IWM_DEVICE_9260_COMMON \ + .device_family = IWM_DEVICE_FAMILY_9000, \ + .eeprom_size = IWM_OTP_LOW_IMAGE_SIZE_FAMILY_9000, \ + .nvm_hw_section_num = IWM_NVM_HW_SECTION_NUM_FAMILY_9260 + +const struct iwm_cfg iwm9260_cfg = { + .name = "Intel(R) Dual Band Wireless AC 9260", + .fw_name = IWM9260_FW, + IWM_DEVICE_9260_COMMON, + .host_interrupt_operation_mode = 0, + .mqrx_supported = 1, +}; diff --git a/sys/dev/iwm/if_iwm_config.h b/sys/dev/iwm/if_iwm_config.h index 4768a16f5261..fabcfaa75184 100644 --- a/sys/dev/iwm/if_iwm_config.h +++ b/sys/dev/iwm/if_iwm_config.h @@ -78,6 +78,7 @@ enum iwm_device_family { IWM_DEVICE_FAMILY_UNDEFINED, IWM_DEVICE_FAMILY_7000, IWM_DEVICE_FAMILY_8000, + IWM_DEVICE_FAMILY_9000, }; #define IWM_DEFAULT_MAX_TX_POWER 22 @@ -130,13 +131,15 @@ enum iwm_nvm_type { */ struct iwm_cfg { const char *name; - const char *fw_name; - uint16_t eeprom_size; - enum iwm_device_family device_family; - int host_interrupt_operation_mode; - uint8_t nvm_hw_section_num; - int apmg_wake_up_wa; - enum iwm_nvm_type nvm_type; + const char *fw_name; + uint16_t eeprom_size; + enum iwm_device_family device_family; + int host_interrupt_operation_mode; + int mqrx_supported; + int integrated; + uint8_t nvm_hw_section_num; + int apmg_wake_up_wa; + enum iwm_nvm_type nvm_type; }; /* @@ -150,5 +153,7 @@ extern const struct iwm_cfg iwm7265_cfg; extern const struct iwm_cfg iwm7265d_cfg; extern const struct iwm_cfg iwm8260_cfg; extern const struct iwm_cfg iwm8265_cfg; +extern const struct iwm_cfg iwm9560_cfg; +extern const struct iwm_cfg iwm9260_cfg; #endif /* __IWM_CONFIG_H__ */ diff --git a/sys/dev/iwm/if_iwm_pcie_trans.c b/sys/dev/iwm/if_iwm_pcie_trans.c index a50e47945812..9178a1d2982f 100644 --- a/sys/dev/iwm/if_iwm_pcie_trans.c +++ b/sys/dev/iwm/if_iwm_pcie_trans.c @@ -185,6 +185,27 @@ iwm_write_prph(struct iwm_softc *sc, uint32_t addr, uint32_t val) IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WDAT, val); } +void +iwm_write_prph64(struct iwm_softc *sc, uint64_t addr, uint64_t val) +{ + iwm_write_prph(sc, (uint32_t)addr, val & 0xffffffff); + iwm_write_prph(sc, (uint32_t)addr + 4, val >> 32); +} + +int +iwm_poll_prph(struct iwm_softc *sc, uint32_t addr, uint32_t bits, uint32_t mask, + int timeout) +{ + do { + if ((iwm_read_prph(sc, addr) & mask) == (bits & mask)) + return (0); + DELAY(10); + timeout -= 10; + } while (timeout > 0); + + return (ETIMEDOUT); +} + #ifdef IWM_DEBUG /* iwlwifi: pcie/trans.c */ int @@ -261,7 +282,7 @@ iwm_nic_lock(struct iwm_softc *sc) IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - if (sc->cfg->device_family == IWM_DEVICE_FAMILY_8000) + if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_8000) DELAY(2); if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, @@ -325,6 +346,8 @@ iwm_enable_rfkill_int(struct iwm_softc *sc) { sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL; IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); + IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); } int @@ -383,7 +406,9 @@ iwm_prepare_card_hw(struct iwm_softc *sc) if (iwm_set_hw_ready(sc)) goto out; - DELAY(100); + IWM_SETBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG, + IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED); + DELAY(1000); /* If HW is not ready, prepare the conditions to check again */ IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, @@ -454,7 +479,7 @@ iwm_apm_init(struct iwm_softc *sc) IWM_DPRINTF(sc, IWM_DEBUG_RESET, "iwm apm start\n"); /* Disable L0S exit timer (platform NMI Work/Around) */ - if (sc->cfg->device_family != IWM_DEVICE_FAMILY_8000) { + if (sc->cfg->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); } @@ -569,6 +594,16 @@ iwm_apm_init(struct iwm_softc *sc) void iwm_apm_stop(struct iwm_softc *sc) { + IWM_SETBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG, + IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED); + IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, + IWM_CSR_HW_IF_CONFIG_REG_PREPARE | + IWM_CSR_HW_IF_CONFIG_REG_ENABLE_PME); + DELAY(1000); + IWM_CLRBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG, + IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED); + DELAY(5000); + /* stop device's busmaster DMA activity */ IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_STOP_MASTER); @@ -576,6 +611,14 @@ iwm_apm_stop(struct iwm_softc *sc) IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100)) device_printf(sc->sc_dev, "timeout waiting for master\n"); + + /* + * Clear "initialization complete" bit to move adapter from + * D0A* (powered-up Active) --> D0U* (Uninitialized) state. + */ + IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, + IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + IWM_DPRINTF(sc, IWM_DEBUG_TRANS, "%s: iwm apm stop\n", __func__); } @@ -590,11 +633,15 @@ iwm_start_hw(struct iwm_softc *sc) /* Reset the entire device */ IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET); - DELAY(10); + DELAY(5000); if ((error = iwm_apm_init(sc)) != 0) return error; + /* On newer chipsets MSI is disabled by default. */ + if (sc->cfg->mqrx_supported) + iwm_write_prph(sc, IWM_UREG_CHICK, IWM_UREG_CHICK_MSI_ENABLE); + iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); @@ -613,13 +660,21 @@ iwm_set_pwr(struct iwm_softc *sc) int iwm_pcie_rx_stop(struct iwm_softc *sc) { - int ret = 0; + int ret; + + ret = 0; if (iwm_nic_lock(sc)) { - IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - ret = iwm_poll_bit(sc, IWM_FH_MEM_RSSR_RX_STATUS_REG, - IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, - IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, - 1000); + if (sc->cfg->mqrx_supported) { + iwm_write_prph(sc, IWM_RFH_RXF_DMA_CFG, 0); + ret = iwm_poll_prph(sc, IWM_RFH_GEN_STATUS, + IWM_RXF_DMA_IDLE, IWM_RXF_DMA_IDLE, 1000); + } else { + IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + ret = iwm_poll_bit(sc, IWM_FH_MEM_RSSR_RX_STATUS_REG, + IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, + IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, + 1000); + } iwm_nic_unlock(sc); } return ret; diff --git a/sys/dev/iwm/if_iwm_pcie_trans.h b/sys/dev/iwm/if_iwm_pcie_trans.h index e04dd52f3fe3..bdbd85476af3 100644 --- a/sys/dev/iwm/if_iwm_pcie_trans.h +++ b/sys/dev/iwm/if_iwm_pcie_trans.h @@ -106,6 +106,10 @@ extern uint32_t iwm_read_prph(struct iwm_softc *sc, uint32_t addr); extern void iwm_write_prph(struct iwm_softc *sc, uint32_t addr, uint32_t val); +extern void iwm_write_prph64(struct iwm_softc *sc, uint64_t addr, + uint64_t val); +extern int iwm_poll_prph(struct iwm_softc *sc, uint32_t addr, uint32_t bits, + uint32_t mask, int timeout); extern int iwm_read_mem(struct iwm_softc *sc, uint32_t addr, void *buf, int dwords); extern int iwm_write_mem(struct iwm_softc *sc, uint32_t addr, const void *buf, int dwords); diff --git a/sys/dev/iwm/if_iwm_scan.c b/sys/dev/iwm/if_iwm_scan.c index 84948cc27829..5a4331b67d07 100644 --- a/sys/dev/iwm/if_iwm_scan.c +++ b/sys/dev/iwm/if_iwm_scan.c @@ -215,8 +215,7 @@ static inline boolean_t iwm_mvm_rrm_scan_needed(struct iwm_softc *sc) { /* require rrm scan whenever the fw supports it */ - return fw_has_capa(&sc->sc_fw.ucode_capa, - IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT); + return iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT); } #ifdef IWM_DEBUG @@ -251,7 +250,7 @@ iwm_mvm_rx_lmac_scan_complete_notif(struct iwm_softc *sc, /* If this happens, the firmware has mistakenly sent an LMAC * notification during UMAC scans -- warn and ignore it. */ - if (fw_has_capa(&sc->sc_fw.ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) { + if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) { device_printf(sc->sc_dev, "%s: Mistakenly got LMAC notification during UMAC scan\n", __func__); @@ -581,6 +580,29 @@ iwm_mvm_scan_use_ebs(struct iwm_softc *sc) sc->last_ebs_successful); } +static int +iwm_mvm_scan_size(struct iwm_softc *sc) +{ + int base_size; + + if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) { + if (iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) + base_size = IWM_SCAN_REQ_UMAC_SIZE_V7; + else + base_size = IWM_SCAN_REQ_UMAC_SIZE_V1; + + return base_size + + sizeof(struct iwm_scan_channel_cfg_umac) * + sc->sc_fw.ucode_capa.n_scan_channels + + sizeof(struct iwm_scan_req_umac_tail); + } else { + return sizeof(struct iwm_scan_req_lmac) + + sizeof(struct iwm_scan_channel_cfg_lmac) * + sc->sc_fw.ucode_capa.n_scan_channels + + sizeof(struct iwm_scan_probe_req); + } +} + int iwm_mvm_umac_scan(struct iwm_softc *sc) { @@ -594,13 +616,11 @@ iwm_mvm_umac_scan(struct iwm_softc *sc) struct iwm_scan_req_umac *req; struct iwm_scan_req_umac_tail *tail; size_t req_len; - uint8_t i, nssid; + uint16_t general_flags; + uint8_t channel_flags, i, nssid; int ret; - req_len = sizeof(struct iwm_scan_req_umac) + - (sizeof(struct iwm_scan_channel_cfg_umac) * - sc->sc_fw.ucode_capa.n_scan_channels) + - sizeof(struct iwm_scan_req_umac_tail); + req_len = iwm_mvm_scan_size(sc); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); @@ -612,28 +632,58 @@ iwm_mvm_umac_scan(struct iwm_softc *sc) 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; + nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); - req->scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); - req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH); + general_flags = IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL | + IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; + if (!iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) + general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL; + if (iwm_mvm_rrm_scan_needed(sc)) + general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED; + if (nssid != 0) + general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; + else + general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE; - nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); - req->n_channels = iwm_mvm_umac_scan_fill_channels(sc, - (struct iwm_scan_channel_cfg_umac *)req->data, nssid); + channel_flags = 0; + if (iwm_mvm_scan_use_ebs(sc)) + channel_flags = IWM_SCAN_CHANNEL_FLAG_EBS | + IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWM_SCAN_CHANNEL_FLAG_CACHE_ADD; - 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); + req->general_flags = htole16(general_flags); + req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH); - tail = (void *)((char *)&req->data + - sizeof(struct iwm_scan_channel_cfg_umac) * - sc->sc_fw.ucode_capa.n_scan_channels); + /* These timings correspond to iwlwifi's UNASSOC scan. */ + if (iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) { + req->v7.active_dwell = 10; + req->v7.passive_dwell = 110; + req->v7.fragmented_dwell = 44; + req->v7.adwell_default_n_aps_social = 10; + req->v7.adwell_default_n_aps = 2; + req->v7.adwell_max_budget = htole16(300); + req->v7.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); + req->v7.channel.flags = channel_flags; + req->v7.channel.count = iwm_mvm_umac_scan_fill_channels(sc, + (struct iwm_scan_channel_cfg_umac *)req->v7.data, nssid); + + tail = (void *)((char *)&req->v7.data + + sizeof(struct iwm_scan_channel_cfg_umac) * + sc->sc_fw.ucode_capa.n_scan_channels); + } else { + req->v1.active_dwell = 10; + req->v1.passive_dwell = 110; + req->v1.fragmented_dwell = 44; + req->v1.extended_dwell = 90; + req->v1.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); + req->v1.channel.flags = channel_flags; + req->v1.channel.count = iwm_mvm_umac_scan_fill_channels(sc, + (struct iwm_scan_channel_cfg_umac *)req->v1.data, nssid); + + tail = (void *)((char *)&req->v1.data + + sizeof(struct iwm_scan_channel_cfg_umac) * + sc->sc_fw.ucode_capa.n_scan_channels); + } /* Check if we're doing an active directed scan. */ for (i = 0; i < nssid; i++) { @@ -644,20 +694,6 @@ iwm_mvm_umac_scan(struct iwm_softc *sc) tail->direct_scan[i].len); /* XXX debug */ } - if (nssid != 0) { - req->general_flags |= - htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT); - } else - req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE); - - if (iwm_mvm_scan_use_ebs(sc)) - req->channel_flags = IWM_SCAN_CHANNEL_FLAG_EBS | - IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | - IWM_SCAN_CHANNEL_FLAG_CACHE_ADD; - - if (iwm_mvm_rrm_scan_needed(sc)) - req->general_flags |= - htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED); ret = iwm_mvm_fill_probe_req(sc, &tail->preq); if (ret) { @@ -695,9 +731,7 @@ iwm_mvm_lmac_scan(struct iwm_softc *sc) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); - req_len = sizeof(struct iwm_scan_req_lmac) + - (sizeof(struct iwm_scan_channel_cfg_lmac) * - sc->sc_fw.ucode_capa.n_scan_channels) + sizeof(struct iwm_scan_probe_req); + req_len = iwm_mvm_scan_size(sc); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); @@ -866,7 +900,7 @@ iwm_mvm_scan_stop_wait(struct iwm_softc *sc) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Preparing to stop scan\n"); - if (fw_has_capa(&sc->sc_fw.ucode_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) + if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) ret = iwm_mvm_umac_scan_abort(sc); else ret = iwm_mvm_lmac_scan_abort(sc); diff --git a/sys/dev/iwm/if_iwm_sta.c b/sys/dev/iwm/if_iwm_sta.c index 507176710c8c..bfbe5b554868 100644 --- a/sys/dev/iwm/if_iwm_sta.c +++ b/sys/dev/iwm/if_iwm_sta.c @@ -138,13 +138,8 @@ __FBSDID("$FreeBSD$"); static inline int iwm_mvm_add_sta_cmd_size(struct iwm_softc *sc) { -#ifdef notyet - return iwm_mvm_has_new_rx_api(mvm) ? - sizeof(struct iwm_mvm_add_sta_cmd) : - sizeof(struct iwm_mvm_add_sta_cmd_v7); -#else - return sizeof(struct iwm_mvm_add_sta_cmd); -#endif + return sc->cfg->mqrx_supported ? sizeof(struct iwm_mvm_add_sta_cmd) : + sizeof(struct iwm_mvm_add_sta_cmd_v7); } /* send station add/update command to firmware */ @@ -318,7 +313,7 @@ iwm_mvm_rm_sta_id(struct iwm_softc *sc, struct ieee80211vap *vap) static int iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta, - const uint8_t *addr, uint16_t mac_id, uint16_t color) + const uint8_t *addr, uint16_t mac_id, uint16_t color) { struct iwm_mvm_add_sta_cmd cmd; int ret; @@ -327,6 +322,8 @@ iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta, memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = sta->sta_id; cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color)); + if (sta->sta_id == IWM_AUX_STA_ID && sc->cfg->mqrx_supported) + cmd.station_type = IWM_STA_AUX_ACTIVITY; cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk); cmd.tid_disable_tx = htole16(0xffff); @@ -362,7 +359,8 @@ iwm_mvm_add_aux_sta(struct iwm_softc *sc) sc->sc_aux_sta.tfd_queue_msk = (1 << IWM_MVM_AUX_QUEUE); /* Map Aux queue to fifo - needs to happen before adding Aux station */ - ret = iwm_enable_txq(sc, 0, IWM_MVM_AUX_QUEUE, IWM_MVM_TX_FIFO_MCAST); + ret = iwm_enable_txq(sc, IWM_AUX_STA_ID, IWM_MVM_AUX_QUEUE, + IWM_MVM_TX_FIFO_MCAST); if (ret) return ret; diff --git a/sys/dev/iwm/if_iwmreg.h b/sys/dev/iwm/if_iwmreg.h index 67f1bbff0f07..950b7da03d4a 100644 --- a/sys/dev/iwm/if_iwmreg.h +++ b/sys/dev/iwm/if_iwmreg.h @@ -289,7 +289,7 @@ #define IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) #define IWM_CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) -#define IWM_CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define IWM_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) @@ -457,6 +457,10 @@ enum iwm_secure_boot_status_reg { #define IWM_LMPM_CHICK 0xa01ff8 #define IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE 0x01 +#define IWM_UREG_CHICK 0xa05c00 +#define IWM_UREG_CHICK_MSI_ENABLE 0x01000000 +#define IWM_UREG_CHICK_MSIX_ENABLE 0x02000000 + #define IWM_FH_TCSR_0_REG0 (0x1D00) /* @@ -635,6 +639,40 @@ P2P_PS_SCM\31UAPSD_SUPPORT\32EBS\33P2P_PS_UAPSD\36BCAST_FILTERING\37GO_UAPSD\40L * 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_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params + * @IWM_UCODE_TLV_API_NEW_VERSION: new versioning format + * @IWM_UCODE_TLV_API_SCAN_TSF_REPORT: Scan start time reported in scan + * iteration complete notification, and the timestamp reported for RX + * received during scan, are reported in TSF of the mac specified in the + * scan request. + * @IWM_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of + * ADD_MODIFY_STA_KEY_API_S_VER_2. + * @IWM_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. + * @IWM_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 + * @IWM_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used + * @IWM_UCODE_TLV_API_QUOTA_LOW_LATENCY: Quota command includes a field + * indicating low latency direction. + * @IWM_UCODE_TLV_API_DEPRECATE_TTAK: RX status flag TTAK ok (bit 7) is + * deprecated. + * @IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2: This ucode supports version 8 + * of scan request: SCAN_REQUEST_CMD_UMAC_API_S_VER_8 + * @IWM_UCODE_TLV_API_FRAG_EBS: This ucode supports fragmented EBS + * @IWM_UCODE_TLV_API_REDUCE_TX_POWER: This ucode supports v5 of + * the REDUCE_TX_POWER_CMD. + * @IWM_UCODE_TLV_API_SHORT_BEACON_NOTIF: This ucode supports the short + * version of the beacon notification. + * @IWM_UCODE_TLV_API_BEACON_FILTER_V4: This ucode supports v4 of + * BEACON_FILTER_CONFIG_API_S_VER_4. + * @IWM_UCODE_TLV_API_REGULATORY_NVM_INFO: This ucode supports v4 of + * REGULATORY_NVM_GET_INFO_RSP_API_S. + * @IWM_UCODE_TLV_API_FTM_NEW_RANGE_REQ: This ucode supports v7 of + * LOCATION_RANGE_REQ_CMD_API_S and v6 of LOCATION_RANGE_RESP_NTFY_API_S. + * @IWM_UCODE_TLV_API_SCAN_OFFLOAD_CHANS: This ucode supports v2 of + * SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S and v3 of + * SCAN_OFFLOAD_PROFILES_QUERY_RSP_S. + * @IWM_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of + * STA_CONTEXT_DOT11AX_API_S + * @IWM_UCODE_TLV_CAPA_SAR_TABLE_VER: This ucode supports different sar + * version tables. * * @IWM_NUM_UCODE_TLV_API: number of bits used */ @@ -642,13 +680,36 @@ enum iwm_ucode_tlv_api { IWM_UCODE_TLV_API_FRAGMENTED_SCAN = 8, IWM_UCODE_TLV_API_WIFI_MCC_UPDATE = 9, IWM_UCODE_TLV_API_LQ_SS_PARAMS = 18, - - IWM_NUM_UCODE_TLV_API = 32 + IWM_UCODE_TLV_API_NEW_VERSION = 20, + IWM_UCODE_TLV_API_SCAN_TSF_REPORT = 28, + IWM_UCODE_TLV_API_TKIP_MIC_KEYS = 29, + IWM_UCODE_TLV_API_STA_TYPE = 30, + IWM_UCODE_TLV_API_NAN2_VER2 = 31, + IWM_UCODE_TLV_API_ADAPTIVE_DWELL = 32, + IWM_UCODE_TLV_API_OCE = 33, + IWM_UCODE_TLV_API_NEW_BEACON_TEMPLATE = 34, + IWM_UCODE_TLV_API_NEW_RX_STATS = 35, + IWM_UCODE_TLV_API_WOWLAN_KEY_MATERIAL = 36, + IWM_UCODE_TLV_API_QUOTA_LOW_LATENCY = 38, + IWM_UCODE_TLV_API_DEPRECATE_TTAK = 41, + IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = 42, + IWM_UCODE_TLV_API_FRAG_EBS = 44, + IWM_UCODE_TLV_API_REDUCE_TX_POWER = 45, + IWM_UCODE_TLV_API_SHORT_BEACON_NOTIF = 46, + IWM_UCODE_TLV_API_BEACON_FILTER_V4 = 47, + IWM_UCODE_TLV_API_REGULATORY_NVM_INFO = 48, + IWM_UCODE_TLV_API_FTM_NEW_RANGE_REQ = 49, + IWM_UCODE_TLV_API_SCAN_OFFLOAD_CHANS = 50, + IWM_UCODE_TLV_API_MBSSID_HE = 52, + IWM_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE = 53, + IWM_UCODE_TLV_API_FTM_RTT_ACCURACY = 54, + IWM_UCODE_TLV_API_SAR_TABLE_VER = 55, + IWM_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = 57, + IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER = 58, + + IWM_NUM_UCODE_TLV_API = 128, }; -#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 @@ -933,6 +994,7 @@ enum iwm_ucode_tlv_type { IWM_UCODE_TLV_FW_DBG_DEST = 38, IWM_UCODE_TLV_FW_DBG_CONF = 39, IWM_UCODE_TLV_FW_DBG_TRIGGER = 40, + IWM_UCODE_TLV_CMD_VERSIONS = 48, IWM_UCODE_TLV_FW_GSCAN_CAPA = 50, IWM_UCODE_TLV_FW_MEM_SEG = 51, }; @@ -1469,6 +1531,52 @@ static inline unsigned int IWM_FH_MEM_CBBC_QUEUE(unsigned int chnl) #define IWM_FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 +/* 9000 rx series registers */ + +#define IWM_RFH_Q0_FRBDCB_BA_LSB 0xa08000 +#define IWM_RFH_Q_FRBDCB_BA_LSB (IWM_RFH_Q0_FRBDCB_BA_LSB + (q) * 8) +/* Write index table */ +#define IWM_RFH_Q0_FRBDCB_WIDX 0xa08080 +#define IWM_RFH_Q_FRBDCB_WIDX (IWM_RFH_Q0_FRBDCB_WIDX + (q) * 4) +/* Write index table - shadow registers */ +#define IWM_RFH_Q0_FRBDCB_WIDX_TRG 0x1c80 +#define IWM_RFH_Q_FRBDCB_WIDX_TRG (IWM_RFH_Q0_FRBDCB_WIDX_TRG + (q) * 4) +/* Read index table */ +#define IWM_RFH_Q0_FRBDCB_RIDX 0xa080c0 +#define IWM_RFH_Q_FRBDCB_RIDX (IWM_RFH_Q0_FRBDCB_RIDX + (q) * 4) +/* Used list table */ +#define IWM_RFH_Q0_URBDCB_BA_LSB 0xa08100 +#define IWM_RFH_Q_URBDCB_BA_LSB (IWM_RFH_Q0_URBDCB_BA_LSB + (q) * 8) +/* Write index table */ +#define IWM_RFH_Q0_URBDCB_WIDX 0xa08180 +#define IWM_RFH_Q_URBDCB_WIDX (IWM_RFH_Q0_URBDCB_WIDX + (q) * 4) +/* stts */ +#define IWM_RFH_Q0_URBD_STTS_WPTR_LSB 0xa08200 +#define IWM_RFH_Q_URBD_STTS_WPTR_LSB (IWM_RFH_Q0_URBD_STTS_WPTR_LSB + (q) * 8) + +#define IWM_RFH_GEN_STATUS 0xa09808 +#define IWM_RXF_DMA_IDLE 0x80000000 + +/* DMA configuration */ +#define IWM_RFH_RXF_DMA_CFG 0xa09820 +#define IWM_RFH_RXF_DMA_RB_SIZE_1K 0x00010000 +#define IWM_RFH_RXF_DMA_RB_SIZE_2K 0x00020000 +#define IWM_RFH_RXF_DMA_RB_SIZE_4K 0x00040000 +#define IWM_RFH_RXF_DMA_RBDCB_SIZE_512 0x00900000 +#define IWM_RFH_RXF_DMA_MIN_RB_4_8 0x03000000 +#define IWM_RFH_RXF_DMA_DROP_TOO_LARGE_MASK 0x04000000 +#define IWM_RFH_DMA_EN_ENABLE_VAL 0x80000000 + +#define IWM_RFH_GEN_CFG 0xa09800 +#define IWM_RFH_GEN_CFG_SERVICE_DMA_SNOOP 0x00000001 +#define IWM_RFH_GEN_CFG_RFH_DMA_SNOOP 0x00000002 +#define IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_128 0x00000010 +#define IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_64 0x00000000 + +#define IWM_RFH_RXF_RXQ_ACTIVE 0xa0980c + +/* end of 9000 rx series registers */ + /* TFDB Area - TFDs buffer table */ #define IWM_FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) #define IWM_FH_TFDIB_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x900) @@ -2799,6 +2907,69 @@ enum iwm_mvm_rx_status { IWM_RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000), }; +enum iwm_rx_mpdu_mac_flags1 { + IWM_RX_MPDU_MFLG1_ADDRTYPE_MASK = 0x03, + IWM_RX_MPDU_MFLG1_MIC_CRC_LEN_MASK = 0xf0, + IWM_RX_MPDU_MFLG1_MIC_CRC_LEN_SHIFT = 3, +}; + +enum iwm_rx_mpdu_mac_flags2 { + IWM_RX_MPDU_MFLG2_HDR_LEN_MASK = 0x1f, + IWM_RX_MPDU_MFLG2_PAD = 0x20, + IWM_RX_MPDU_MFLG2_AMSDU = 0x40, +}; + +enum iwm_rx_mpdu_phy_info { + IWM_RX_MPDU_PHY_AMPDU = (1 << 5), + IWM_RX_MPDU_PHY_AMPDU_TOGGLE = (1 << 6), + IWM_RX_MPDU_PHY_SHORT_PREAMBLE = (1 << 7), + IWM_RX_MPDU_PHY_NCCK_ADDTL_NTFY = (1 << 7), + IWM_RX_MPDU_PHY_TSF_OVERLOAD = (1 << 8), +}; + +struct iwm_rx_mpdu_desc_v1 { + union { + uint32_t rss_hash; + uint32_t phy_data2; + }; + union { + uint32_t filter_match; + uint32_t phy_data3; + }; + uint32_t rate_n_flags; + uint8_t energy_a; + uint8_t energy_b; + uint8_t channel; + uint8_t mac_context; + uint32_t gp2_on_air_rise; + union { + uint64_t tsf_on_air_rise; + struct { + uint32_t phy_data0; + uint32_t phy_data1; + }; + }; +} __packed; + +struct iwm_rx_mpdu_desc { + uint16_t mpdu_len; + uint8_t mac_flags1; + uint8_t mac_flags2; + uint8_t amsdu_info; + uint16_t phy_info; + uint8_t mac_phy_idx; + uint16_t raw_csum; + union { + uint16_t l3l4_flags; + uint16_t phy_data4; + }; + uint16_t status; + uint8_t hash_filter; + uint8_t sta_id_flags; + uint32_t reorder_data; + struct iwm_rx_mpdu_desc_v1 v1; +} __packed; + /** * struct iwm_radio_version_notif - information on the radio version * ( IWM_RADIO_VERSION_NOTIFICATION = 0x68 ) @@ -4306,13 +4477,41 @@ enum iwm_tx_pm_timeouts { #define IWM_BAR_DFAULT_RETRY_LIMIT 60 #define IWM_LOW_RETRY_LIMIT 7 +/** + * enum iwm_tx_offload_assist_flags_pos - set %iwm_tx_cmd offload_assist values + * @IWM_TX_CMD_OFFLD_IP_HDR: offset to start of IP header (in words) + * from mac header end. For normal case it is 4 words for SNAP. + * note: tx_cmd, mac header and pad are not counted in the offset. + * This is used to help the offload in case there is tunneling such as + * IPv6 in IPv4, in such case the ip header offset should point to the + * inner ip header and IPv4 checksum of the external header should be + * calculated by driver. + * @IWM_TX_CMD_OFFLD_L4_EN: enable TCP/UDP checksum + * @IWM_TX_CMD_OFFLD_L3_EN: enable IP header checksum + * @IWM_TX_CMD_OFFLD_MH_SIZE: size of the mac header in words. Includes the IV + * field. Doesn't include the pad. + * @IWM_TX_CMD_OFFLD_PAD: mark 2-byte pad was inserted after the mac header for + * alignment + * @IWM_TX_CMD_OFFLD_AMSDU: mark TX command is A-MSDU + */ +enum iwm_tx_offload_assist_flags_pos { + IWM_TX_CMD_OFFLD_IP_HDR = 0, + IWM_TX_CMD_OFFLD_L4_EN = 6, + IWM_TX_CMD_OFFLD_L3_EN = 7, + IWM_TX_CMD_OFFLD_MH_SIZE = 8, + IWM_TX_CMD_OFFLD_PAD = 13, + IWM_TX_CMD_OFFLD_AMSDU = 14, +}; + +#define IWM_TX_CMD_OFFLD_MH_MASK 0x1f +#define IWM_TX_CMD_OFFLD_IP_HDR_MASK 0x3f + /* TODO: complete documentation for try_cnt and btkill_cnt */ /** * struct iwm_tx_cmd - TX command struct to FW * ( IWM_TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details - * @next_frame_len: same as len, but for next frame (0 if not applicable) - * Used for fragmentation and bursting, but not in 11n aggregation. + * @offload_assist: TX offload configuration * @tx_flags: combination of IWM_TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if IWM_TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of IWM_RATE_MCS_* @@ -4348,7 +4547,7 @@ enum iwm_tx_pm_timeouts { */ struct iwm_tx_cmd { uint16_t len; - uint16_t next_frame_len; + uint16_t offload_assist; uint32_t tx_flags; struct { uint8_t try_cnt; @@ -4361,8 +4560,7 @@ struct iwm_tx_cmd { uint8_t initial_rate_index; uint8_t reserved2; uint8_t key[16]; - uint16_t next_frame_flags; - uint16_t reserved3; + uint32_t reserved3; uint32_t life_time; uint32_t dram_lsb_ptr; uint8_t dram_msb_ptr; @@ -4370,7 +4568,7 @@ struct iwm_tx_cmd { uint8_t data_retry_limit; uint8_t tid_tspec; uint16_t pm_frame_timeout; - uint16_t driver_txop; + uint16_t reserved4; uint8_t payload[0]; struct ieee80211_frame hdr[0]; } __packed; /* IWM_TX_CMD_API_S_VER_3 */ @@ -5289,22 +5487,45 @@ struct iwm_scan_req_umac_tail { struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX]; } __packed; +/** + * struct iwm_scan_uma_chan_param + * @flags: channel flags &enum iwm_scan_channel_flags + * @count: num of channels in scan request + * @reserved: for future use and alignment + */ +struct iwm_scan_umac_chan_param { + uint8_t flags; + uint8_t count; + uint16_t reserved; +} __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 + * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @extended_dwell: dwell time for channels 1, 6 and 11 - * @active_dwell: dwell time for active scan - * @passive_dwell: dwell time for passive scan + * @active_dwell: dwell time for active scan per LMAC + * @passive_dwell: dwell time for passive scan per LMAC * @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 + * @adwell_default_n_aps: for adaptive dwell the default number of APs + * per channel + * @adwell_default_n_aps_social: for adaptive dwell the default + * number of APs per social (1,6,11) channel + * @general_flags2: &enum iwl_umac_scan_general_flags2 + * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added + * to total scan time + * @max_out_time: max out of serving channel time, per LMAC - for CDB there + * are 2 LMACs + * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs + * @scan_priority: scan internal prioritization &enum iwl_scan_priority + * @num_of_fragments: Number of fragments needed for full coverage per band. + * Relevant only for fragmented scan. + * @channel: &struct iwl_scan_umac_chan_param * @reserved: for future use and alignment + * @reserved3: for future use and alignment * @data: &struct iwm_scan_channel_cfg_umac and * &struct iwm_scan_req_umac_tail */ @@ -5312,21 +5533,40 @@ 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 */ + uint16_t general_flags; + uint8_t reserved; + uint8_t scan_start_mac_id; + union { + struct { + 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; + struct iwm_scan_umac_chan_param channel; + uint8_t data[]; + } v1; + struct { + uint8_t active_dwell; + uint8_t passive_dwell; + uint8_t fragmented_dwell; + uint8_t adwell_default_n_aps; + uint8_t adwell_default_n_aps_social; + uint8_t reserved3; + uint16_t adwell_max_budget; + uint32_t max_out_time[2]; + uint32_t suspend_time[2]; + uint32_t scan_priority; + struct iwm_scan_umac_chan_param channel; + uint8_t data[]; + } v7; + }; +} __packed; + +#define IWM_SCAN_REQ_UMAC_SIZE_V7 48 +#define IWM_SCAN_REQ_UMAC_SIZE_V1 36 /** * struct iwm_umac_scan_abort @@ -5636,30 +5876,34 @@ struct iwm_mvm_keyinfo { #define IWM_ADD_STA_BAID_SHIFT 8 /** - * struct iwm_mvm_add_sta_cmd - Add/modify a station in the fw's sta table. + * struct iwl_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 - * @awake_acs: + * @add_modify: see &enum iwl_sta_mode + * @awake_acs: ACs to transmit data on while station is sleeping (for U-APSD) * @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 + * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. + * @mac_id_n_color: the Mac context this station belongs to, + * see &enum iwl_ctxt_id_and_color + * @addr: station's MAC address + * @reserved2: reserved * @sta_id: index of station in uCode's station table - * @modify_mask: IWM_STA_MODIFY_*, selects which parameters to modify vs. leave + * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. - * @station_flags: look at %iwm_sta_flags - * @station_flags_msk: what of %station_flags have changed + * @reserved3: reserved + * @station_flags: look at &enum iwl_sta_flags + * @station_flags_msk: what of %station_flags have changed, + * also &enum iwl_sta_flags * @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 + * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) - * Set %IWM_STA_MODIFY_REMOVE_BA_TID to use this field + * Set %STA_MODIFY_REMOVE_BA_TID to use this field * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with * add_immediate_ba_tid. * @sleep_tx_count: number of packets to transmit to station even though it is * asleep. Used to synchronise PS-poll and u-APSD responses while ucode * keeps track of STA sleep state. - * @sleep_state_flags: Look at %iwm_sta_sleep_flag. + * @sleep_state_flags: Look at &enum iwl_sta_sleep_flag. * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls @@ -5667,12 +5911,12 @@ struct iwm_mvm_keyinfo { * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx - * attempt and any retries (set by IWM_REPLY_TX_LINK_QUALITY_CMD). + * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD). * * 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 { +struct iwm_mvm_add_sta_cmd_v7 { uint8_t add_modify; uint8_t awake_acs; uint16_t tid_disable_tx; @@ -5691,9 +5935,100 @@ struct iwm_mvm_add_sta_cmd { uint16_t sleep_state_flags; uint16_t assoc_id; uint16_t beamform_flags; - uint32_t tfd_queue_msk; + uint16_t tfd_queue_msk; } __packed; /* ADD_STA_CMD_API_S_VER_7 */ +/** + * enum iwm_sta_type - FW station types + * ( REPLY_ADD_STA = 0x18 ) + * @IWM_STA_LINK: Link station - normal RX and TX traffic. + * @IWM_STA_GENERAL_PURPOSE: General purpose. In AP mode used for beacons + * and probe responses. + * @IWM_STA_MULTICAST: multicast traffic, + * @IWM_STA_TDLS_LINK: TDLS link station + * @IWM_STA_AUX_ACTIVITY: auxilary station (scan, ROC and so on). + */ +enum iwm_sta_type { + IWM_STA_LINK, + IWM_STA_GENERAL_PURPOSE, + IWM_STA_MULTICAST, + IWM_STA_TDLS_LINK, + IWM_STA_AUX_ACTIVITY, +}; + +/** + * struct iwm_mvm_add_sta_cmd - Add/modify a station in the fw's sta table. + * ( REPLY_ADD_STA = 0x18 ) + * @add_modify: see &enum iwm_sta_mode + * @awake_acs: ACs to transmit data on while station is sleeping (for U-APSD) + * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable + * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. + * @mac_id_n_color: the Mac context this station belongs to, + * see &enum iwl_ctxt_id_and_color + * @addr: station's MAC address + * @reserved2: reserved + * @sta_id: index of station in uCode's station table + * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave + * alone. 1 - modify, 0 - don't change. + * @reserved3: reserved + * @station_flags: look at &enum iwm_sta_flags + * @station_flags_msk: what of %station_flags have changed, + * also &enum iwm_sta_flags + * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) + * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set + * add_immediate_ba_ssn. + * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) + * Set %STA_MODIFY_REMOVE_BA_TID to use this field + * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with + * add_immediate_ba_tid. + * @sleep_tx_count: number of packets to transmit to station even though it is + * asleep. Used to synchronise PS-poll and u-APSD responses while ucode + * keeps track of STA sleep state. + * @station_type: type of this station. See &enum iwl_sta_type. + * @sleep_state_flags: Look at &enum iwl_sta_sleep_flag. + * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP + * mac-addr. + * @beamform_flags: beam forming controls + * @tfd_queue_msk: tfd queues used by this station. + * Obselete for new TX API (9 and above). + * @rx_ba_window: aggregation window size + * @sp_length: the size of the SP in actual number of frames + * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver + * enabled ACs. + * + * The device contains an internal table of per-station information, with info + * on security keys, aggregation parameters, and Tx rates for initial Tx + * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD). + * + * 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 { + uint8_t add_modify; + 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 */ + uint16_t reserved2; + uint8_t sta_id; + uint8_t modify_mask; + uint16_t reserved3; + uint32_t station_flags; + uint32_t station_flags_msk; + uint8_t add_immediate_ba_tid; + uint8_t remove_immediate_ba_tid; + uint16_t add_immediate_ba_ssn; + uint16_t sleep_tx_count; + uint8_t sleep_state_flags; + uint8_t station_type; + uint16_t assoc_id; + uint16_t beamform_flags; + uint32_t tfd_queue_msk; + uint16_t rx_ba_window; + uint8_t sp_length; + uint8_t uapsd_acs; +} __packed; /* ADD_STA_CMD_API_S_VER_10 */ + /** * struct iwm_mvm_add_sta_key_cmd - add/modify sta key * ( IWM_REPLY_ADD_STA_KEY = 0x17 ) diff --git a/sys/dev/iwm/if_iwmvar.h b/sys/dev/iwm/if_iwmvar.h index 4f303d1ec8de..353d5e921a26 100644 --- a/sys/dev/iwm/if_iwmvar.h +++ b/sys/dev/iwm/if_iwmvar.h @@ -165,20 +165,6 @@ struct iwm_ucode_capabilities { uint8_t enabled_capa[howmany(IWM_NUM_UCODE_TLV_CAPA, NBBY)]; }; -static inline int -fw_has_api(const struct iwm_ucode_capabilities *capabilities, - unsigned int api) -{ - return isset(capabilities->enabled_api, api); -} - -static inline int -fw_has_capa(const struct iwm_ucode_capabilities *capabilities, - unsigned int capa) -{ - return isset(capabilities->enabled_capa, capa); -} - /* one for each uCode image (inst/data, init/runtime/wowlan) */ struct iwm_fw_desc { const void *data; /* vmalloc'ed data */ @@ -299,11 +285,12 @@ struct iwm_tx_ring { int cur; }; -#define IWM_RX_RING_COUNT 256 -/* Linux driver optionally uses 8k buffer */ +#define IWM_RX_LEGACY_RING_COUNT 256 +#define IWM_RX_MQ_RING_COUNT 512 + #define IWM_RBUF_SIZE 4096 -#define IWM_MAX_SCATTER 20 +#define IWM_MAX_SCATTER 20 struct iwm_rx_data { struct mbuf *m; @@ -311,12 +298,13 @@ struct iwm_rx_data { }; struct iwm_rx_ring { - struct iwm_dma_info desc_dma; + struct iwm_dma_info free_desc_dma; + struct iwm_dma_info used_desc_dma; struct iwm_dma_info stat_dma; struct iwm_dma_info buf_dma; - uint32_t *desc; + void *desc; struct iwm_rb_status *stat; - struct iwm_rx_data data[IWM_RX_RING_COUNT]; + struct iwm_rx_data data[512]; bus_dmamap_t spare_map; /* for iwm_rx_addbuf() */ bus_dma_tag_t data_dmat; int cur; @@ -459,8 +447,6 @@ struct iwm_softc { struct iwm_rx_ring rxq; int qfullmsk; - int sc_sf_state; - /* ICT table. */ struct iwm_dma_info ict_dma; int ict_cur; @@ -526,8 +512,6 @@ struct iwm_softc { struct iwm_notif_statistics_v10 sc_stats; int sc_noise; - caddr_t sc_drvbpf; - struct iwm_rx_radiotap_header sc_rxtap; struct iwm_tx_radiotap_header sc_txtap; @@ -580,3 +564,15 @@ struct iwm_softc { #define IWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define IWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define IWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) + +static inline bool +iwm_fw_has_api(struct iwm_softc *sc, unsigned int api) +{ + return isset(sc->sc_fw.ucode_capa.enabled_api, api); +} + +static inline bool +iwm_fw_has_capa(struct iwm_softc *sc, unsigned int capa) +{ + return isset(sc->sc_fw.ucode_capa.enabled_capa, capa); +} diff --git a/sys/modules/iwm/Makefile b/sys/modules/iwm/Makefile index 58153c84662e..809cb4b3e85b 100644 --- a/sys/modules/iwm/Makefile +++ b/sys/modules/iwm/Makefile @@ -7,7 +7,8 @@ KMOD= if_iwm SRCS= if_iwm.c if_iwm_binding.c if_iwm_util.c if_iwm_phy_db.c SRCS+= if_iwm_mac_ctxt.c if_iwm_phy_ctxt.c if_iwm_time_event.c SRCS+= if_iwm_power.c if_iwm_scan.c if_iwm_led.c if_iwm_notif_wait.c -SRCS+= if_iwm_7000.c if_iwm_8000.c if_iwm_fw.c if_iwm_sta.c if_iwm_sf.c +SRCS+= if_iwm_7000.c if_iwm_8000.c if_iwm_9000.c if_iwm_fw.c if_iwm_9260.c +SRCS+= if_iwm_sta.c if_iwm_sf.c # bus layer SRCS+= if_iwm_pcie_trans.c SRCS+= device_if.h bus_if.h pci_if.h opt_wlan.h opt_iwm.h