diff options
Diffstat (limited to 'drivers/net/wireless')
370 files changed, 24987 insertions, 6553 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8f5a3f4a43f2..166920ae23f8 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -45,6 +45,7 @@ source "drivers/net/wireless/rsi/Kconfig" source "drivers/net/wireless/st/Kconfig" source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zydas/Kconfig" +source "drivers/net/wireless/quantenna/Kconfig" config PCMCIA_RAYCS tristate "Aviator/Raytheon 2.4GHz wireless support" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index f00d42953fb8..54b41ac5f9c8 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ +obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index ed626f568b58..3b0802fc5bf5 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -390,9 +390,9 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) priv->pdev, priv->rx_buffers[entry].mapping, pktlen, PCI_DMA_FROMDEVICE); - memcpy(skb_put(skb, pktlen), - skb_tail_pointer(priv->rx_buffers[entry].skb), - pktlen); + skb_put_data(skb, + skb_tail_pointer(priv->rx_buffers[entry].skb), + pktlen); pci_dma_sync_single_for_device( priv->pdev, priv->rx_buffers[entry].mapping, @@ -1700,7 +1700,7 @@ static void adm8211_tx(struct ieee80211_hw *dev, skb_pull(skb, hdrlen); payload_len = skb->len; - txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr)); + txhdr = skb_push(skb, sizeof(*txhdr)); memset(txhdr, 0, sizeof(*txhdr)); memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN); txhdr->signal = plcp_signal; diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index f2f4ccfdf8da..106d6f8d471a 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -829,8 +829,8 @@ static void ar5523_tx_work_locked(struct ar5523 *ar) data->ar = ar; data->urb = urb; - desc = (struct ar5523_tx_desc *)skb_push(skb, sizeof(*desc)); - chunk = (struct ar5523_chunk *)skb_push(skb, sizeof(*chunk)); + desc = skb_push(skb, sizeof(*desc)); + chunk = skb_push(skb, sizeof(*chunk)); chunk->seqnum = 0; chunk->flags = UATH_CFLAGS_FINAL; diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index b4241cf9b7ed..412eb1380dcc 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -22,6 +22,13 @@ config ATH10K_AHB ---help--- This module adds support for AHB bus +config ATH10K_SDIO + tristate "Atheros ath10k SDIO support (EXPERIMENTAL)" + depends on ATH10K && MMC + ---help--- + This module adds experimental support for SDIO/MMC bus. Currently + work in progress and will not fully work. + config ATH10K_DEBUG bool "Atheros ath10k debugging" depends on ATH10K diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 930fadd940d8..b0b19a7eb98b 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -27,5 +27,8 @@ ath10k_pci-y += pci.o \ ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o +obj-$(CONFIG_ATH10K_SDIO) += ath10k_sdio.o +ath10k_sdio-y += sdio.o + # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index abeee200310b..2d3a2f31123d 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -97,6 +97,77 @@ int ath10k_bmi_get_target_info(struct ath10k *ar, return 0; } +#define TARGET_VERSION_SENTINAL 0xffffffffu + +int ath10k_bmi_get_target_info_sdio(struct ath10k *ar, + struct bmi_target_info *target_info) +{ + struct bmi_cmd cmd; + union bmi_resp resp; + u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info); + u32 resplen, ver_len; + __le32 tmp; + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n"); + + if (ar->bmi.done_sent) { + ath10k_warn(ar, "BMI Get Target Info Command disallowed\n"); + return -EBUSY; + } + + cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO); + + /* Step 1: Read 4 bytes of the target info and check if it is + * the special sentinal version word or the first word in the + * version response. + */ + resplen = sizeof(u32); + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen); + if (ret) { + ath10k_warn(ar, "unable to read from device\n"); + return ret; + } + + /* Some SDIO boards have a special sentinal byte before the real + * version response. + */ + if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) { + /* Step 1b: Read the version length */ + resplen = sizeof(u32); + ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp, + &resplen); + if (ret) { + ath10k_warn(ar, "unable to read from device\n"); + return ret; + } + } + + ver_len = __le32_to_cpu(tmp); + + /* Step 2: Check the target info length */ + if (ver_len != sizeof(resp.get_target_info)) { + ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n", + ver_len, sizeof(resp.get_target_info)); + return -EINVAL; + } + + /* Step 3: Read the rest of the version response */ + resplen = sizeof(resp.get_target_info) - sizeof(u32); + ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, + &resp.get_target_info.version, + &resplen); + if (ret) { + ath10k_warn(ar, "unable to read from device\n"); + return ret; + } + + target_info->version = __le32_to_cpu(resp.get_target_info.version); + target_info->type = __le32_to_cpu(resp.get_target_info.type); + + return 0; +} + int ath10k_bmi_read_memory(struct ath10k *ar, u32 address, void *buffer, u32 length) { diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index cc45b63ade15..9c0839b2ca8f 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -83,6 +83,8 @@ enum bmi_cmd_id { #define BMI_NVRAM_SEG_NAME_SZ 16 #define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10 +#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000 +#define BMI_PARAM_FLASH_SECTION_ALL 0x10000 #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00 #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10 @@ -188,8 +190,8 @@ struct bmi_target_info { u32 type; }; -/* in msec */ -#define BMI_COMMUNICATION_TIMEOUT_HZ (2 * HZ) +/* in jiffies */ +#define BMI_COMMUNICATION_TIMEOUT_HZ (3 * HZ) #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 @@ -198,6 +200,8 @@ void ath10k_bmi_start(struct ath10k *ar); int ath10k_bmi_done(struct ath10k *ar); int ath10k_bmi_get_target_info(struct ath10k *ar, struct bmi_target_info *target_info); +int ath10k_bmi_get_target_info_sdio(struct ath10k *ar, + struct bmi_target_info *target_info); int ath10k_bmi_read_memory(struct ath10k *ar, u32 address, void *buffer, u32 length); int ath10k_bmi_write_memory(struct ath10k *ar, u32 address, diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index ee1090ca2eac..08b84c8c3614 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -59,205 +59,243 @@ * the buffer is sent/received. */ +static inline unsigned int +ath10k_set_ring_byte(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map) +{ + return ((offset << addr_map->lsb) & addr_map->mask); +} + +static inline unsigned int +ath10k_get_ring_byte(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map) +{ + return ((offset & addr_map->mask) >> (addr_map->lsb)); +} + static inline void ath10k_ce_dest_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dst_wr_index_addr, n); } static inline u32 ath10k_ce_dest_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dst_wr_index_addr); } static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_wr_index_addr, n); } static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_wr_index_addr); } static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_SRRI_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_srri_addr); } static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_BA_ADDRESS, addr); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_base_addr, addr); } static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_SIZE_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_size_addr, n); } static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32((ar), - (ce_ctrl_addr) + CE_CTRL1_ADDRESS); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ath10k_pci_read32(ar, + ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, - (ctrl1_addr & ~CE_CTRL1_DMAX_LENGTH_MASK) | - CE_CTRL1_DMAX_LENGTH_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dmax->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->dmax)); } static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, - (ctrl1_addr & ~CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) | - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->src_ring->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->src_ring)); } static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, - (ctrl1_addr & ~CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) | - CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dst_ring->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->dst_ring)); } static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_DRRI_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_drri_addr); } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, u32 addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_BA_ADDRESS, addr); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_base_addr, addr); } static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_SIZE_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_size_addr, n); } static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + srcr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, - (addr & ~SRC_WATERMARK_HIGH_MASK) | - SRC_WATERMARK_HIGH_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_high->mask)) | + (ath10k_set_ring_byte(n, srcr_wm->wm_high))); } static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + srcr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, - (addr & ~SRC_WATERMARK_LOW_MASK) | - SRC_WATERMARK_LOW_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_low->mask)) | + (ath10k_set_ring_byte(n, srcr_wm->wm_low))); } static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + dstr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, - (addr & ~DST_WATERMARK_HIGH_MASK) | - DST_WATERMARK_HIGH_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_high->mask)) | + (ath10k_set_ring_byte(n, dstr_wm->wm_high))); } static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + dstr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, - (addr & ~DST_WATERMARK_LOW_MASK) | - DST_WATERMARK_LOW_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_low->mask)) | + (ath10k_set_ring_byte(n, dstr_wm->wm_low))); } static inline void ath10k_ce_copy_complete_inter_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; + u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr | HOST_IE_COPY_COMPLETE_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr | host_ie->copy_complete->mask); } static inline void ath10k_ce_copy_complete_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; + u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr & ~HOST_IE_COPY_COMPLETE_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(host_ie->copy_complete->mask)); } static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; + u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr & ~CE_WATERMARK_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(wm_regs->wm_mask)); } static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + MISC_IE_ADDRESS); + struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; + u32 misc_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->misc_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, - misc_ie_addr | CE_ERROR_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr | misc_regs->err_mask); } static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + MISC_IE_ADDRESS); + struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; + u32 misc_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->misc_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, - misc_ie_addr & ~CE_ERROR_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr & ~(misc_regs->err_mask)); } static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int mask) { - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; + + ath10k_pci_write32(ar, ce_ctrl_addr + wm_regs->addr, mask); } /* @@ -594,6 +632,7 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, unsigned int nentries_mask = src_ring->nentries_mask; unsigned int sw_index = src_ring->sw_index; unsigned int read_index; + struct ce_desc *desc; if (src_ring->hw_index == sw_index) { /* @@ -623,6 +662,9 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, /* sanity */ src_ring->per_transfer_context[sw_index] = NULL; + desc = CE_SRC_RING_TO_DESC(src_ring->base_addr_owner_space, + sw_index); + desc->nbytes = 0; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); @@ -715,13 +757,13 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; u32 ctrl_addr = ce_state->ctrl_addr; spin_lock_bh(&ar_pci->ce_lock); /* Clear the copy-complete interrupts that will be handled here. */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, - HOST_IS_COPY_COMPLETE_MASK); + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->cc_mask); spin_unlock_bh(&ar_pci->ce_lock); @@ -737,7 +779,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) * Misc CE interrupts are not being handled, but still need * to be cleared. */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK); + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask); spin_unlock_bh(&ar_pci->ce_lock); } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index e76a98242b98..95743a57525d 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -263,143 +263,11 @@ struct ce_attr { void (*recv_cb)(struct ath10k_ce_pipe *); }; -#define SR_BA_ADDRESS 0x0000 -#define SR_SIZE_ADDRESS 0x0004 -#define DR_BA_ADDRESS 0x0008 -#define DR_SIZE_ADDRESS 0x000c -#define CE_CMD_ADDRESS 0x0018 - -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MSB 17 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MSB 16 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_GET(x) \ - (((x) & CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) >> \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_DMAX_LENGTH_MSB 15 -#define CE_CTRL1_DMAX_LENGTH_LSB 0 -#define CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff -#define CE_CTRL1_DMAX_LENGTH_GET(x) \ - (((x) & CE_CTRL1_DMAX_LENGTH_MASK) >> CE_CTRL1_DMAX_LENGTH_LSB) -#define CE_CTRL1_DMAX_LENGTH_SET(x) \ - (((0 | (x)) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) - -#define CE_CTRL1_ADDRESS 0x0010 -#define CE_CTRL1_HW_MASK 0x0007ffff -#define CE_CTRL1_SW_MASK 0x0007ffff -#define CE_CTRL1_HW_WRITE_MASK 0x00000000 -#define CE_CTRL1_SW_WRITE_MASK 0x0007ffff -#define CE_CTRL1_RSTMASK 0xffffffff -#define CE_CTRL1_RESET 0x00000080 - -#define CE_CMD_HALT_STATUS_MSB 3 -#define CE_CMD_HALT_STATUS_LSB 3 -#define CE_CMD_HALT_STATUS_MASK 0x00000008 -#define CE_CMD_HALT_STATUS_GET(x) \ - (((x) & CE_CMD_HALT_STATUS_MASK) >> CE_CMD_HALT_STATUS_LSB) -#define CE_CMD_HALT_STATUS_SET(x) \ - (((0 | (x)) << CE_CMD_HALT_STATUS_LSB) & CE_CMD_HALT_STATUS_MASK) -#define CE_CMD_HALT_STATUS_RESET 0 -#define CE_CMD_HALT_MSB 0 -#define CE_CMD_HALT_MASK 0x00000001 - -#define HOST_IE_COPY_COMPLETE_MSB 0 -#define HOST_IE_COPY_COMPLETE_LSB 0 -#define HOST_IE_COPY_COMPLETE_MASK 0x00000001 -#define HOST_IE_COPY_COMPLETE_GET(x) \ - (((x) & HOST_IE_COPY_COMPLETE_MASK) >> HOST_IE_COPY_COMPLETE_LSB) -#define HOST_IE_COPY_COMPLETE_SET(x) \ - (((0 | (x)) << HOST_IE_COPY_COMPLETE_LSB) & HOST_IE_COPY_COMPLETE_MASK) -#define HOST_IE_COPY_COMPLETE_RESET 0 -#define HOST_IE_ADDRESS 0x002c - -#define HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 -#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 -#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 -#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 -#define HOST_IS_COPY_COMPLETE_MASK 0x00000001 -#define HOST_IS_ADDRESS 0x0030 - -#define MISC_IE_ADDRESS 0x0034 - -#define MISC_IS_AXI_ERR_MASK 0x00000400 - -#define MISC_IS_DST_ADDR_ERR_MASK 0x00000200 -#define MISC_IS_SRC_LEN_ERR_MASK 0x00000100 -#define MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 -#define MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 -#define MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 - -#define MISC_IS_ADDRESS 0x0038 - -#define SR_WR_INDEX_ADDRESS 0x003c - -#define DST_WR_INDEX_ADDRESS 0x0040 - -#define CURRENT_SRRI_ADDRESS 0x0044 - -#define CURRENT_DRRI_ADDRESS 0x0048 - -#define SRC_WATERMARK_LOW_MSB 31 -#define SRC_WATERMARK_LOW_LSB 16 -#define SRC_WATERMARK_LOW_MASK 0xffff0000 -#define SRC_WATERMARK_LOW_GET(x) \ - (((x) & SRC_WATERMARK_LOW_MASK) >> SRC_WATERMARK_LOW_LSB) -#define SRC_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) -#define SRC_WATERMARK_LOW_RESET 0 -#define SRC_WATERMARK_HIGH_MSB 15 -#define SRC_WATERMARK_HIGH_LSB 0 -#define SRC_WATERMARK_HIGH_MASK 0x0000ffff -#define SRC_WATERMARK_HIGH_GET(x) \ - (((x) & SRC_WATERMARK_HIGH_MASK) >> SRC_WATERMARK_HIGH_LSB) -#define SRC_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) -#define SRC_WATERMARK_HIGH_RESET 0 -#define SRC_WATERMARK_ADDRESS 0x004c - -#define DST_WATERMARK_LOW_LSB 16 -#define DST_WATERMARK_LOW_MASK 0xffff0000 -#define DST_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) -#define DST_WATERMARK_LOW_RESET 0 -#define DST_WATERMARK_HIGH_MSB 15 -#define DST_WATERMARK_HIGH_LSB 0 -#define DST_WATERMARK_HIGH_MASK 0x0000ffff -#define DST_WATERMARK_HIGH_GET(x) \ - (((x) & DST_WATERMARK_HIGH_MASK) >> DST_WATERMARK_HIGH_LSB) -#define DST_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) -#define DST_WATERMARK_HIGH_RESET 0 -#define DST_WATERMARK_ADDRESS 0x0050 - static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) { return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; } -#define CE_WATERMARK_MASK (HOST_IS_SRC_RING_LOW_WATERMARK_MASK | \ - HOST_IS_SRC_RING_HIGH_WATERMARK_MASK | \ - HOST_IS_DST_RING_LOW_WATERMARK_MASK | \ - HOST_IS_DST_RING_HIGH_WATERMARK_MASK) - -#define CE_ERROR_MASK (MISC_IS_AXI_ERR_MASK | \ - MISC_IS_DST_ADDR_ERR_MASK | \ - MISC_IS_SRC_LEN_ERR_MASK | \ - MISC_IS_DST_MAX_LEN_VIO_MASK | \ - MISC_IS_DST_RING_OVERFLOW_MASK | \ - MISC_IS_SRC_RING_OVERFLOW_MASK) - #define CE_SRC_RING_TO_DESC(baddr, idx) \ (&(((struct ce_desc *)baddr)[idx])) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5a0638915874..75c5c903c8a6 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -72,6 +72,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA9887_HW_1_0_VERSION, @@ -93,6 +95,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_2_1_VERSION, @@ -113,6 +117,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_2_1_VERSION, @@ -133,6 +139,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_3_0_VERSION, @@ -153,6 +161,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_3_2_VERSION, @@ -176,6 +186,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_cpu_freq = 176000000, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -202,6 +214,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 4, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -229,6 +243,12 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 12, + + /* Can do only 2x2 VHT160 or 80+80. 1560Mbps is 4x4 80Mhz + * or 2x2 160Mhz, long-guard-interval. + */ + .vht160_mcs_rx_highest = 1560, + .vht160_mcs_tx_highest = 1560, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -255,6 +275,12 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 12, + + /* Can do only 1x1 VHT160 or 80+80. 780Mbps is 2x2 80Mhz or + * 1x1 160Mhz, long-guard-interval. + */ + .vht160_mcs_rx_highest = 780, + .vht160_mcs_tx_highest = 780, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -275,6 +301,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -297,6 +325,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_cpu_freq = 176000000, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -324,6 +354,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 4, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, }; @@ -389,6 +421,21 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) complete(&ar->target_suspend); } +static void ath10k_init_sdio(struct ath10k *ar) +{ + u32 param = 0; + + ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); + ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); + ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + + param |= (HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET | + HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET | + HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE); + + ath10k_bmi_write32(ar, hi_acs_flags, param); +} + static int ath10k_init_configure_target(struct ath10k *ar) { u32 param_host; @@ -676,7 +723,7 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; u8 board_id, chip_id; - int ret; + int ret, bmi_board_id_param; address = ar->hw_params.patch_load_addr; @@ -700,8 +747,13 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) return ret; } - ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID, - &result); + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID; + else + bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID; + + ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result); if (ret) { ath10k_err(ar, "could not execute otp for board id check: %d\n", ret); @@ -830,6 +882,11 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) return ret; } + /* As of now pre-cal is valid for 10_4 variants */ + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); if (ret) { ath10k_err(ar, "could not execute otp (%d)\n", ret); @@ -1395,7 +1452,18 @@ err: static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name, size_t fw_name_len, int fw_api) { - scnprintf(fw_name, fw_name_len, "%s-%d.bin", ATH10K_FW_FILE_BASE, fw_api); + switch (ar->hif.bus) { + case ATH10K_BUS_SDIO: + scnprintf(fw_name, fw_name_len, "%s-%s-%d.bin", + ATH10K_FW_FILE_BASE, ath10k_bus_str(ar->hif.bus), + fw_api); + break; + case ATH10K_BUS_PCI: + case ATH10K_BUS_AHB: + scnprintf(fw_name, fw_name_len, "%s-%d.bin", + ATH10K_FW_FILE_BASE, fw_api); + break; + } } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) @@ -1953,6 +2021,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (status) goto err; + if (ar->hif.bus == ATH10K_BUS_SDIO) + ath10k_init_sdio(ar); + ar->htc.htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; @@ -2200,7 +2271,10 @@ static int ath10k_core_probe_fw(struct ath10k *ar) } memset(&target_info, 0, sizeof(target_info)); - ret = ath10k_bmi_get_target_info(ar, &target_info); + if (ar->hif.bus == ATH10K_BUS_SDIO) + ret = ath10k_bmi_get_target_info_sdio(ar, &target_info); + else + ret = ath10k_bmi_get_target_info(ar, &target_info); if (ret) { ath10k_err(ar, "could not get target info (%d)\n", ret); goto err_power_down; @@ -2417,24 +2491,29 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, case ATH10K_HW_QCA988X: case ATH10K_HW_QCA9887: ar->regs = &qca988x_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca988x_values; break; case ATH10K_HW_QCA6174: case ATH10K_HW_QCA9377: ar->regs = &qca6174_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca6174_values; break; case ATH10K_HW_QCA99X0: case ATH10K_HW_QCA9984: ar->regs = &qca99x0_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca99x0_values; break; case ATH10K_HW_QCA9888: ar->regs = &qca99x0_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca9888_values; break; case ATH10K_HW_QCA4019: ar->regs = &qca4019_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca4019_values; break; default: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index bf091514ecc6..1aa5cf12fce0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -91,6 +91,7 @@ struct ath10k; enum ath10k_bus { ATH10K_BUS_PCI, ATH10K_BUS_AHB, + ATH10K_BUS_SDIO, }; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -100,6 +101,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) return "pci"; case ATH10K_BUS_AHB: return "ahb"; + case ATH10K_BUS_SDIO: + return "sdio"; } return "unknown"; @@ -791,6 +794,7 @@ struct ath10k { struct completion target_suspend; const struct ath10k_hw_regs *regs; + const struct ath10k_hw_ce_regs *hw_ce_regs; const struct ath10k_hw_values *hw_values; struct ath10k_bmi bmi; struct ath10k_wmi wmi; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 4cd2a0fd49d6..389fcb7a9fd0 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -625,17 +625,21 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - char buf[32]; + char buf[32] = {0}; + ssize_t rc; int ret; - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + /* filter partial writes and invalid commands */ + if (*ppos != 0 || count >= sizeof(buf) || count == 0) + return -EINVAL; - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = 0; + rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + if (rc < 0) + return rc; /* drop the possible '\n' from the end */ - if (buf[count - 1] == '\n') - buf[count - 1] = 0; + if (buf[*ppos - 1] == '\n') + buf[*ppos - 1] = '\0'; mutex_lock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 2368f47314ae..257d10985c6e 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -38,6 +38,8 @@ enum ath10k_debug_mask { ATH10K_DBG_WMI_PRINT = 0x00002000, ATH10K_DBG_PCI_PS = 0x00004000, ATH10K_DBG_AHB = 0x00008000, + ATH10K_DBG_SDIO = 0x00010000, + ATH10K_DBG_SDIO_DUMP = 0x00020000, ATH10K_DBG_ANY = 0xffffffff, }; diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index b7669b2e94aa..e5c80f582ff5 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -57,8 +57,8 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc, skb_pull(skb, sizeof(struct ath10k_htc_hdr)); } -static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, - struct sk_buff *skb) +void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, + struct sk_buff *skb) { struct ath10k *ar = ep->htc->ar; @@ -75,6 +75,7 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, ep->ep_ops.ep_tx_complete(ep->htc->ar, skb); } +EXPORT_SYMBOL(ath10k_htc_notify_tx_completion); static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep, struct sk_buff *skb) @@ -230,12 +231,79 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc, spin_unlock_bh(&htc->tx_lock); } -static int ath10k_htc_process_trailer(struct ath10k_htc *htc, - u8 *buffer, - int length, - enum ath10k_htc_ep_id src_eid) +static int +ath10k_htc_process_lookahead(struct ath10k_htc *htc, + const struct ath10k_htc_lookahead_report *report, + int len, + enum ath10k_htc_ep_id eid, + void *next_lookaheads, + int *next_lookaheads_len) { struct ath10k *ar = htc->ar; + + /* Invalid lookahead flags are actually transmitted by + * the target in the HTC control message. + * Since this will happen at every boot we silently ignore + * the lookahead in this case + */ + if (report->pre_valid != ((~report->post_valid) & 0xFF)) + return 0; + + if (next_lookaheads && next_lookaheads_len) { + ath10k_dbg(ar, ATH10K_DBG_HTC, + "htc rx lookahead found pre_valid 0x%x post_valid 0x%x\n", + report->pre_valid, report->post_valid); + + /* look ahead bytes are valid, copy them over */ + memcpy((u8 *)next_lookaheads, report->lookahead, 4); + + *next_lookaheads_len = 1; + } + + return 0; +} + +static int +ath10k_htc_process_lookahead_bundle(struct ath10k_htc *htc, + const struct ath10k_htc_lookahead_bundle *report, + int len, + enum ath10k_htc_ep_id eid, + void *next_lookaheads, + int *next_lookaheads_len) +{ + struct ath10k *ar = htc->ar; + int bundle_cnt = len / sizeof(*report); + + if (!bundle_cnt || (bundle_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE)) { + ath10k_warn(ar, "Invalid lookahead bundle count: %d\n", + bundle_cnt); + return -EINVAL; + } + + if (next_lookaheads && next_lookaheads_len) { + int i; + + for (i = 0; i < bundle_cnt; i++) { + memcpy(((u8 *)next_lookaheads) + 4 * i, + report->lookahead, 4); + report++; + } + + *next_lookaheads_len = bundle_cnt; + } + + return 0; +} + +int ath10k_htc_process_trailer(struct ath10k_htc *htc, + u8 *buffer, + int length, + enum ath10k_htc_ep_id src_eid, + void *next_lookaheads, + int *next_lookaheads_len) +{ + struct ath10k_htc_lookahead_bundle *bundle; + struct ath10k *ar = htc->ar; int status = 0; struct ath10k_htc_record *record; u8 *orig_buffer; @@ -274,6 +342,29 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, record->hdr.len, src_eid); break; + case ATH10K_HTC_RECORD_LOOKAHEAD: + len = sizeof(struct ath10k_htc_lookahead_report); + if (record->hdr.len < len) { + ath10k_warn(ar, "Lookahead report too long\n"); + status = -EINVAL; + break; + } + status = ath10k_htc_process_lookahead(htc, + record->lookahead_report, + record->hdr.len, + src_eid, + next_lookaheads, + next_lookaheads_len); + break; + case ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE: + bundle = record->lookahead_bundle; + status = ath10k_htc_process_lookahead_bundle(htc, + bundle, + record->hdr.len, + src_eid, + next_lookaheads, + next_lookaheads_len); + break; default: ath10k_warn(ar, "Unhandled record: id:%d length:%d\n", record->hdr.id, record->hdr.len); @@ -294,6 +385,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, return status; } +EXPORT_SYMBOL(ath10k_htc_process_trailer); void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) { @@ -360,7 +452,8 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) trailer += payload_len; trailer -= trailer_len; status = ath10k_htc_process_trailer(htc, trailer, - trailer_len, hdr->eid); + trailer_len, hdr->eid, + NULL, NULL); if (status) goto out; @@ -371,42 +464,6 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) /* zero length packet with trailer data, just drop these */ goto out; - if (eid == ATH10K_HTC_EP_0) { - struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data; - - switch (__le16_to_cpu(msg->hdr.message_id)) { - case ATH10K_HTC_MSG_READY_ID: - case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID: - /* handle HTC control message */ - if (completion_done(&htc->ctl_resp)) { - /* - * this is a fatal error, target should not be - * sending unsolicited messages on the ep 0 - */ - ath10k_warn(ar, "HTC rx ctrl still processing\n"); - complete(&htc->ctl_resp); - goto out; - } - - htc->control_resp_len = - min_t(int, skb->len, - ATH10K_HTC_MAX_CTRL_MSG_LEN); - - memcpy(htc->control_resp_buffer, skb->data, - htc->control_resp_len); - - complete(&htc->ctl_resp); - break; - case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE: - htc->htc_ops.target_send_suspend_complete(ar); - break; - default: - ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n"); - break; - } - goto out; - } - ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %pK\n", eid, skb); ep->ep_ops.ep_rx_complete(ar, skb); @@ -421,10 +478,40 @@ EXPORT_SYMBOL(ath10k_htc_rx_completion_handler); static void ath10k_htc_control_rx_complete(struct ath10k *ar, struct sk_buff *skb) { - /* This is unexpected. FW is not supposed to send regular rx on this - * endpoint. - */ - ath10k_warn(ar, "unexpected htc rx\n"); + struct ath10k_htc *htc = &ar->htc; + struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data; + + switch (__le16_to_cpu(msg->hdr.message_id)) { + case ATH10K_HTC_MSG_READY_ID: + case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID: + /* handle HTC control message */ + if (completion_done(&htc->ctl_resp)) { + /* this is a fatal error, target should not be + * sending unsolicited messages on the ep 0 + */ + ath10k_warn(ar, "HTC rx ctrl still processing\n"); + complete(&htc->ctl_resp); + goto out; + } + + htc->control_resp_len = + min_t(int, skb->len, + ATH10K_HTC_MAX_CTRL_MSG_LEN); + + memcpy(htc->control_resp_buffer, skb->data, + htc->control_resp_len); + + complete(&htc->ctl_resp); + break; + case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE: + htc->htc_ops.target_send_suspend_complete(ar); + break; + default: + ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n"); + break; + } + +out: kfree_skb(skb); } @@ -497,12 +584,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) struct ath10k *ar = htc->ar; int i, status = 0; unsigned long time_left; - struct ath10k_htc_svc_conn_req conn_req; - struct ath10k_htc_svc_conn_resp conn_resp; struct ath10k_htc_msg *msg; u16 message_id; - u16 credit_count; - u16 credit_size; time_left = wait_for_completion_timeout(&htc->ctl_resp, ATH10K_HTC_WAIT_TIMEOUT_HZ); @@ -539,16 +622,14 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) msg = (struct ath10k_htc_msg *)htc->control_resp_buffer; message_id = __le16_to_cpu(msg->hdr.message_id); - credit_count = __le16_to_cpu(msg->ready.credit_count); - credit_size = __le16_to_cpu(msg->ready.credit_size); if (message_id != ATH10K_HTC_MSG_READY_ID) { ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id); return -ECOMM; } - htc->total_transmit_credits = credit_count; - htc->target_credit_size = credit_size; + htc->total_transmit_credits = __le16_to_cpu(msg->ready.credit_count); + htc->target_credit_size = __le16_to_cpu(msg->ready.credit_size); ath10k_dbg(ar, ATH10K_DBG_HTC, "Target ready! transmit resources: %d size:%d\n", @@ -561,20 +642,17 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) return -ECOMM; } - /* setup our pseudo HTC control endpoint connection */ - memset(&conn_req, 0, sizeof(conn_req)); - memset(&conn_resp, 0, sizeof(conn_resp)); - conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete; - conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete; - conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS; - conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL; - - /* connect fake service */ - status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); - if (status) { - ath10k_err(ar, "could not connect to htc service (%d)\n", - status); - return status; + /* The only way to determine if the ready message is an extended + * message is from the size. + */ + if (htc->control_resp_len >= + sizeof(msg->hdr) + sizeof(msg->ready_ext)) { + htc->max_msgs_per_htc_bundle = + min_t(u8, msg->ready_ext.max_msgs_per_htc_bundle, + HTC_HOST_MAX_MSG_PER_BUNDLE); + ath10k_dbg(ar, ATH10K_DBG_HTC, + "Extended ready message. RX bundle size: %d\n", + htc->max_msgs_per_htc_bundle); } return 0; @@ -772,6 +850,13 @@ int ath10k_htc_start(struct ath10k_htc *htc) msg->hdr.message_id = __cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID); + if (ar->hif.bus == ATH10K_BUS_SDIO) { + /* Extra setup params used by SDIO */ + msg->setup_complete_ext.flags = + __cpu_to_le32(ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN); + msg->setup_complete_ext.max_msgs_per_bundled_recv = + htc->max_msgs_per_htc_bundle; + } ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n"); status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb); @@ -786,8 +871,10 @@ int ath10k_htc_start(struct ath10k_htc *htc) /* registered target arrival callback from the HIF layer */ int ath10k_htc_init(struct ath10k *ar) { - struct ath10k_htc_ep *ep = NULL; + int status; struct ath10k_htc *htc = &ar->htc; + struct ath10k_htc_svc_conn_req conn_req; + struct ath10k_htc_svc_conn_resp conn_resp; spin_lock_init(&htc->tx_lock); @@ -795,10 +882,21 @@ int ath10k_htc_init(struct ath10k *ar) htc->ar = ar; - /* Get HIF default pipe for HTC message exchange */ - ep = &htc->endpoint[ATH10K_HTC_EP_0]; + /* setup our pseudo HTC control endpoint connection */ + memset(&conn_req, 0, sizeof(conn_req)); + memset(&conn_resp, 0, sizeof(conn_resp)); + conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete; + conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete; + conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS; + conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL; - ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id); + /* connect fake service */ + status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); + if (status) { + ath10k_err(ar, "could not connect to htc service (%d)\n", + status); + return status; + } init_completion(&htc->ctl_resp); diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 6ababa345e2b..24663b07eeac 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -50,6 +50,8 @@ struct ath10k; * 4-byte aligned. */ +#define HTC_HOST_MAX_MSG_PER_BUNDLE 8 + enum ath10k_htc_tx_flags { ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01, ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02 @@ -110,6 +112,10 @@ enum ath10k_htc_conn_svc_status { ATH10K_HTC_CONN_SVC_STATUS_NO_MORE_EP = 4 }; +enum ath10k_htc_setup_complete_flags { + ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN = 1 +}; + struct ath10k_ath10k_htc_msg_hdr { __le16 message_id; /* @enum htc_message_id */ } __packed; @@ -174,8 +180,10 @@ struct ath10k_htc_msg { } __packed __aligned(4); enum ath10k_ath10k_htc_record_id { - ATH10K_HTC_RECORD_NULL = 0, - ATH10K_HTC_RECORD_CREDITS = 1 + ATH10K_HTC_RECORD_NULL = 0, + ATH10K_HTC_RECORD_CREDITS = 1, + ATH10K_HTC_RECORD_LOOKAHEAD = 2, + ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE = 3, }; struct ath10k_ath10k_htc_record_hdr { @@ -192,10 +200,28 @@ struct ath10k_htc_credit_report { u8 pad1; } __packed; +struct ath10k_htc_lookahead_report { + u8 pre_valid; + u8 pad0; + u8 pad1; + u8 pad2; + u8 lookahead[4]; + u8 post_valid; + u8 pad3; + u8 pad4; + u8 pad5; +} __packed; + +struct ath10k_htc_lookahead_bundle { + u8 lookahead[4]; +} __packed; + struct ath10k_htc_record { struct ath10k_ath10k_htc_record_hdr hdr; union { struct ath10k_htc_credit_report credit_report[0]; + struct ath10k_htc_lookahead_report lookahead_report[0]; + struct ath10k_htc_lookahead_bundle lookahead_bundle[0]; u8 pauload[0]; }; } __packed __aligned(4); @@ -338,6 +364,7 @@ struct ath10k_htc { int total_transmit_credits; int target_credit_size; + u8 max_msgs_per_htc_bundle; }; int ath10k_htc_init(struct ath10k *ar); @@ -351,5 +378,13 @@ int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size); void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb); void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb); +void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, + struct sk_buff *skb); +int ath10k_htc_process_trailer(struct ath10k_htc *htc, + u8 *buffer, + int length, + enum ath10k_htc_ep_id src_eid, + void *next_lookaheads, + int *next_lookaheads_len); #endif diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 84b6067ff6e7..398dda978d6e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -829,6 +829,19 @@ static void ath10k_htt_rx_h_signal(struct ath10k *ar, struct ieee80211_rx_status *status, struct htt_rx_desc *rxd) { + int i; + + for (i = 0; i < IEEE80211_MAX_CHAINS ; i++) { + status->chains &= ~BIT(i); + + if (rxd->ppdu_start.rssi_chains[i].pri20_mhz != 0x80) { + status->chain_signal[i] = ATH10K_DEFAULT_NOISE_FLOOR + + rxd->ppdu_start.rssi_chains[i].pri20_mhz; + + status->chains |= BIT(i); + } + } + /* FIXME: Get real NF */ status->signal = ATH10K_DEFAULT_NOISE_FLOOR + rxd->ppdu_start.rssi_comb; @@ -2229,9 +2242,15 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, txrate.mcs = ATH10K_HW_MCS_RATE(peer_stats->ratecode); sgi = ATH10K_HW_GI(peer_stats->flags); - if (((txrate.flags == WMI_RATE_PREAMBLE_HT) || - (txrate.flags == WMI_RATE_PREAMBLE_VHT)) && txrate.mcs > 9) { - ath10k_warn(ar, "Invalid mcs %hhd peer stats", txrate.mcs); + if (txrate.flags == WMI_RATE_PREAMBLE_VHT && txrate.mcs > 9) { + ath10k_warn(ar, "Invalid VHT mcs %hhd peer stats", txrate.mcs); + return; + } + + if (txrate.flags == WMI_RATE_PREAMBLE_HT && + (txrate.mcs > 7 || txrate.nss < 1)) { + ath10k_warn(ar, "Invalid HT mcs %hhd nss %hhd peer stats", + txrate.mcs, txrate.nss); return; } @@ -2254,7 +2273,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, arsta->txrate.legacy = rate; } else if (txrate.flags == WMI_RATE_PREAMBLE_HT) { arsta->txrate.flags = RATE_INFO_FLAGS_MCS; - arsta->txrate.mcs = txrate.mcs; + arsta->txrate.mcs = txrate.mcs + 8 * (txrate.nss - 1); } else { arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; arsta->txrate.mcs = txrate.mcs; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index c866ab524571..afb0c01cbb55 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -15,6 +15,7 @@ */ #include <linux/types.h> +#include <linux/bitops.h> #include "core.h" #include "hw.h" #include "hif.h" @@ -191,6 +192,142 @@ const struct ath10k_hw_values qca4019_values = { .ce_desc_meta_data_lsb = 4, }; +static struct ath10k_hw_ce_regs_addr_map qcax_src_ring = { + .msb = 0x00000010, + .lsb = 0x00000010, + .mask = GENMASK(16, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dst_ring = { + .msb = 0x00000011, + .lsb = 0x00000011, + .mask = GENMASK(17, 17), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dmax = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_ctrl1 qcax_ctrl1 = { + .addr = 0x00000010, + .hw_mask = 0x0007ffff, + .sw_mask = 0x0007ffff, + .hw_wr_mask = 0x00000000, + .sw_wr_mask = 0x0007ffff, + .reset_mask = 0xffffffff, + .reset = 0x00000080, + .src_ring = &qcax_src_ring, + .dst_ring = &qcax_dst_ring, + .dmax = &qcax_dmax, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_cmd_halt_status = { + .msb = 0x00000003, + .lsb = 0x00000003, + .mask = GENMASK(3, 3), +}; + +static struct ath10k_hw_ce_cmd_halt qcax_cmd_halt = { + .msb = 0x00000000, + .mask = GENMASK(0, 0), + .status_reset = 0x00000000, + .status = &qcax_cmd_halt_status, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_host_ie_cc = { + .msb = 0x00000000, + .lsb = 0x00000000, + .mask = GENMASK(0, 0), +}; + +static struct ath10k_hw_ce_host_ie qcax_host_ie = { + .copy_complete_reset = 0x00000000, + .copy_complete = &qcax_host_ie_cc, +}; + +static struct ath10k_hw_ce_host_wm_regs qcax_wm_reg = { + .dstr_lmask = 0x00000010, + .dstr_hmask = 0x00000008, + .srcr_lmask = 0x00000004, + .srcr_hmask = 0x00000002, + .cc_mask = 0x00000001, + .wm_mask = 0x0000001E, + .addr = 0x00000030, +}; + +static struct ath10k_hw_ce_misc_regs qcax_misc_reg = { + .axi_err = 0x00000400, + .dstr_add_err = 0x00000200, + .srcr_len_err = 0x00000100, + .dstr_mlen_vio = 0x00000080, + .dstr_overflow = 0x00000040, + .srcr_overflow = 0x00000020, + .err_mask = 0x000007E0, + .addr = 0x00000038, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_src_wm_low = { + .msb = 0x0000001f, + .lsb = 0x00000010, + .mask = GENMASK(31, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_src_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_dst_src_wm_regs qcax_wm_src_ring = { + .addr = 0x0000004c, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &qcax_src_wm_low, + .wm_high = &qcax_src_wm_high, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dst_wm_low = { + .lsb = 0x00000010, + .mask = GENMASK(31, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dst_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_dst_src_wm_regs qcax_wm_dst_ring = { + .addr = 0x00000050, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &qcax_dst_wm_low, + .wm_high = &qcax_dst_wm_high, +}; + +struct ath10k_hw_ce_regs qcax_ce_regs = { + .sr_base_addr = 0x00000000, + .sr_size_addr = 0x00000004, + .dr_base_addr = 0x00000008, + .dr_size_addr = 0x0000000c, + .ce_cmd_addr = 0x00000018, + .misc_ie_addr = 0x00000034, + .sr_wr_index_addr = 0x0000003c, + .dst_wr_index_addr = 0x00000040, + .current_srri_addr = 0x00000044, + .current_drri_addr = 0x00000048, + .host_ie_addr = 0x0000002c, + .ctrl1_regs = &qcax_ctrl1, + .cmd_halt = &qcax_cmd_halt, + .host_ie = &qcax_host_ie, + .wm_regs = &qcax_wm_reg, + .misc_regs = &qcax_misc_reg, + .wm_srcr = &qcax_wm_src_ring, + .wm_dstr = &qcax_wm_dst_ring, +}; + const struct ath10k_hw_clk_params qca6174_clk[ATH10K_HW_REFCLK_COUNT] = { { .refclk = 48000000, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5b1e90bb2a4d..97dc1479f44e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -268,6 +268,86 @@ extern const struct ath10k_hw_regs qca6174_regs; extern const struct ath10k_hw_regs qca99x0_regs; extern const struct ath10k_hw_regs qca4019_regs; +struct ath10k_hw_ce_regs_addr_map { + u32 msb; + u32 lsb; + u32 mask; +}; + +struct ath10k_hw_ce_ctrl1 { + u32 addr; + u32 hw_mask; + u32 sw_mask; + u32 hw_wr_mask; + u32 sw_wr_mask; + u32 reset_mask; + u32 reset; + struct ath10k_hw_ce_regs_addr_map *src_ring; + struct ath10k_hw_ce_regs_addr_map *dst_ring; + struct ath10k_hw_ce_regs_addr_map *dmax; }; + +struct ath10k_hw_ce_cmd_halt { + u32 status_reset; + u32 msb; + u32 mask; + struct ath10k_hw_ce_regs_addr_map *status; }; + +struct ath10k_hw_ce_host_ie { + u32 copy_complete_reset; + struct ath10k_hw_ce_regs_addr_map *copy_complete; }; + +struct ath10k_hw_ce_host_wm_regs { + u32 dstr_lmask; + u32 dstr_hmask; + u32 srcr_lmask; + u32 srcr_hmask; + u32 cc_mask; + u32 wm_mask; + u32 addr; +}; + +struct ath10k_hw_ce_misc_regs { + u32 axi_err; + u32 dstr_add_err; + u32 srcr_len_err; + u32 dstr_mlen_vio; + u32 dstr_overflow; + u32 srcr_overflow; + u32 err_mask; + u32 addr; +}; + +struct ath10k_hw_ce_dst_src_wm_regs { + u32 addr; + u32 low_rst; + u32 high_rst; + struct ath10k_hw_ce_regs_addr_map *wm_low; + struct ath10k_hw_ce_regs_addr_map *wm_high; }; + +struct ath10k_hw_ce_regs { + u32 sr_base_addr; + u32 sr_size_addr; + u32 dr_base_addr; + u32 dr_size_addr; + u32 ce_cmd_addr; + u32 misc_ie_addr; + u32 sr_wr_index_addr; + u32 dst_wr_index_addr; + u32 current_srri_addr; + u32 current_drri_addr; + u32 ddr_addr_for_rri_low; + u32 ddr_addr_for_rri_high; + u32 ce_rri_low; + u32 ce_rri_high; + u32 host_ie_addr; + struct ath10k_hw_ce_host_wm_regs *wm_regs; + struct ath10k_hw_ce_misc_regs *misc_regs; + struct ath10k_hw_ce_ctrl1 *ctrl1_regs; + struct ath10k_hw_ce_cmd_halt *cmd_halt; + struct ath10k_hw_ce_host_ie *host_ie; + struct ath10k_hw_ce_dst_src_wm_regs *wm_srcr; + struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr; }; + struct ath10k_hw_values { u32 rtc_state_val_on; u8 ce_count; @@ -282,6 +362,7 @@ extern const struct ath10k_hw_values qca6174_values; extern const struct ath10k_hw_values qca99x0_values; extern const struct ath10k_hw_values qca9888_values; extern const struct ath10k_hw_values qca4019_values; +extern struct ath10k_hw_ce_regs qcax_ce_regs; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); @@ -454,6 +535,12 @@ struct ath10k_hw_params { /* Number of bytes to be discarded for each FFT sample */ int spectral_bin_discard; + + /* The board may have a restricted NSS for 160 or 80+80 vs what it + * can do for 80Mhz. + */ + int vht160_mcs_rx_highest; + int vht160_mcs_tx_highest; }; struct htt_rx_desc; @@ -863,6 +950,59 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, #define QCA9887_EEPROM_ADDR_LO_MASK 0x00ff0000 #define QCA9887_EEPROM_ADDR_LO_LSB 16 +#define MBOX_RESET_CONTROL_ADDRESS 0x00000000 +#define MBOX_HOST_INT_STATUS_ADDRESS 0x00000800 +#define MBOX_HOST_INT_STATUS_ERROR_LSB 7 +#define MBOX_HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define MBOX_HOST_INT_STATUS_CPU_LSB 6 +#define MBOX_HOST_INT_STATUS_CPU_MASK 0x00000040 +#define MBOX_HOST_INT_STATUS_COUNTER_LSB 4 +#define MBOX_HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define MBOX_CPU_INT_STATUS_ADDRESS 0x00000801 +#define MBOX_ERROR_INT_STATUS_ADDRESS 0x00000802 +#define MBOX_ERROR_INT_STATUS_WAKEUP_LSB 2 +#define MBOX_ERROR_INT_STATUS_WAKEUP_MASK 0x00000004 +#define MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1 +#define MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002 +#define MBOX_ERROR_INT_STATUS_TX_OVERFLOW_LSB 0 +#define MBOX_ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001 +#define MBOX_COUNTER_INT_STATUS_ADDRESS 0x00000803 +#define MBOX_COUNTER_INT_STATUS_COUNTER_LSB 0 +#define MBOX_COUNTER_INT_STATUS_COUNTER_MASK 0x000000ff +#define MBOX_RX_LOOKAHEAD_VALID_ADDRESS 0x00000805 +#define MBOX_INT_STATUS_ENABLE_ADDRESS 0x00000828 +#define MBOX_INT_STATUS_ENABLE_ERROR_LSB 7 +#define MBOX_INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define MBOX_INT_STATUS_ENABLE_CPU_LSB 6 +#define MBOX_INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define MBOX_INT_STATUS_ENABLE_INT_LSB 5 +#define MBOX_INT_STATUS_ENABLE_INT_MASK 0x00000020 +#define MBOX_INT_STATUS_ENABLE_COUNTER_LSB 4 +#define MBOX_INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define MBOX_INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define MBOX_INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define MBOX_CPU_INT_STATUS_ENABLE_ADDRESS 0x00000819 +#define MBOX_CPU_INT_STATUS_ENABLE_BIT_LSB 0 +#define MBOX_CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define MBOX_ERROR_STATUS_ENABLE_ADDRESS 0x0000081a +#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1 +#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002 +#define MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0 +#define MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001 +#define MBOX_COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000081b +#define MBOX_COUNTER_INT_STATUS_ENABLE_BIT_LSB 0 +#define MBOX_COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define MBOX_COUNT_ADDRESS 0x00000820 +#define MBOX_COUNT_DEC_ADDRESS 0x00000840 +#define MBOX_WINDOW_DATA_ADDRESS 0x00000874 +#define MBOX_WINDOW_WRITE_ADDR_ADDRESS 0x00000878 +#define MBOX_WINDOW_READ_ADDR_ADDRESS 0x0000087c +#define MBOX_CPU_DBG_SEL_ADDRESS 0x00000883 +#define MBOX_CPU_DBG_ADDRESS 0x00000884 +#define MBOX_RTC_BASE_ADDRESS 0x00000000 +#define MBOX_GPIO_BASE_ADDRESS 0x00005000 +#define MBOX_MBOX_BASE_ADDRESS 0x00008000 + #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) /* Register definitions for first generation ath10k cards. These cards include diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4674ff33d320..55c808f03a84 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1392,7 +1392,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronize setup for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -2519,6 +2519,20 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", sta->addr, arg->peer_max_mpdu, arg->peer_flags); + + if (arg->peer_vht_rates.rx_max_rate && + (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) { + switch (arg->peer_vht_rates.rx_max_rate) { + case 1560: + /* Must be 2x2 at 160Mhz is all it can do. */ + arg->peer_bw_rxnss_override = 2; + break; + case 780: + /* Can only do 1x1 at 160Mhz (Long Guard Interval) */ + arg->peer_bw_rxnss_override = 1; + break; + } + } } static void ath10k_peer_assoc_h_qos(struct ath10k *ar, @@ -3475,9 +3489,8 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, if (arvif->u.ap.noa_data) if (!pskb_expand_head(skb, 0, arvif->u.ap.noa_len, GFP_ATOMIC)) - memcpy(skb_put(skb, arvif->u.ap.noa_len), - arvif->u.ap.noa_data, - arvif->u.ap.noa_len); + skb_put_data(skb, arvif->u.ap.noa_data, + arvif->u.ap.noa_len); spin_unlock_bh(&ar->data_lock); } } @@ -4362,6 +4375,7 @@ static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar) static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ath10k_hw_params *hw = &ar->hw_params; u16 mcs_map; u32 val; int i; @@ -4391,7 +4405,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) * mode until that's resolved. */ if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) && - !(ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) + (ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0) vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; mcs_map = 0; @@ -4408,6 +4422,17 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + /* If we are supporting 160Mhz or 80+80, then the NIC may be able to do + * a restricted NSS for 160 or 80+80 vs what it can do for 80Mhz. Give + * user-space a clue if that is the case. + */ + if ((vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) && + (hw->vht160_mcs_rx_highest != 0 || + hw->vht160_mcs_tx_highest != 0)) { + vht_cap.vht_mcs.rx_highest = cpu_to_le16(hw->vht160_mcs_rx_highest); + vht_cap.vht_mcs.tx_highest = cpu_to_le16(hw->vht160_mcs_tx_highest); + } + return vht_cap; } @@ -6073,6 +6098,20 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ar->num_stations + 1, ar->max_num_stations, ar->num_peers + 1, ar->max_num_peers); + num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif); + num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw); + + if (sta->tdls) { + if (num_tdls_stations >= ar->max_num_tdls_vdevs) { + ath10k_warn(ar, "vdev %i exceeded maximum number of tdls vdevs %i\n", + arvif->vdev_id, + ar->max_num_tdls_vdevs); + ret = -ELNRNG; + goto exit; + } + peer_type = WMI_PEER_TYPE_TDLS; + } + ret = ath10k_mac_inc_num_stations(arvif, sta); if (ret) { ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n", @@ -6080,9 +6119,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, goto exit; } - if (sta->tdls) - peer_type = WMI_PEER_TYPE_TDLS; - ret = ath10k_peer_create(ar, vif, sta, arvif->vdev_id, sta->addr, peer_type); if (ret) { @@ -6113,35 +6149,17 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, if (!sta->tdls) goto exit; - num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif); - num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw); - - if (num_tdls_vifs >= ar->max_num_tdls_vdevs && - num_tdls_stations == 0) { - ath10k_warn(ar, "vdev %i exceeded maximum number of tdls vdevs %i\n", - arvif->vdev_id, ar->max_num_tdls_vdevs); - ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); + ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, + WMI_TDLS_ENABLE_ACTIVE); + if (ret) { + ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n", + arvif->vdev_id, ret); + ath10k_peer_delete(ar, arvif->vdev_id, + sta->addr); ath10k_mac_dec_num_stations(arvif, sta); - ret = -ENOBUFS; goto exit; } - if (num_tdls_stations == 0) { - /* This is the first tdls peer in current vif */ - enum wmi_tdls_state state = WMI_TDLS_ENABLE_ACTIVE; - - ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, - state); - if (ret) { - ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n", - arvif->vdev_id, ret); - ath10k_peer_delete(ar, arvif->vdev_id, - sta->addr); - ath10k_mac_dec_num_stations(arvif, sta); - goto exit; - } - } - ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta, WMI_TDLS_PEER_STATE_PEERING); if (ret) { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1e9806f57ee4..7ebfc409018d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -101,7 +101,8 @@ static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); static int ath10k_pci_request_irq(struct ath10k *ar); static void ath10k_pci_free_irq(struct ath10k *ar); -static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, +static int ath10k_pci_bmi_wait(struct ath10k *ar, + struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); @@ -468,7 +469,7 @@ static int ath10k_pci_wake_wait(struct ath10k *ar) while (tot_delay < PCIE_WAKE_TIMEOUT) { if (ath10k_pci_is_awake(ar)) { if (tot_delay > PCIE_WAKE_LATE_US) - ath10k_warn(ar, "device wakeup took %d ms which is unusally long, otherwise it works normally.\n", + ath10k_warn(ar, "device wakeup took %d ms which is unusually long, otherwise it works normally.\n", tot_delay / 1000); return 0; } @@ -1846,7 +1847,7 @@ int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, if (ret) goto err_resp; - ret = ath10k_pci_bmi_wait(ce_tx, ce_rx, &xfer); + ret = ath10k_pci_bmi_wait(ar, ce_tx, ce_rx, &xfer); if (ret) { u32 unused_buffer; unsigned int unused_nbytes; @@ -1913,23 +1914,37 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) xfer->rx_done = true; } -static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, +static int ath10k_pci_bmi_wait(struct ath10k *ar, + struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer) { unsigned long timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + unsigned long started = jiffies; + unsigned long dur; + int ret; while (time_before_eq(jiffies, timeout)) { ath10k_pci_bmi_send_done(tx_pipe); ath10k_pci_bmi_recv_data(rx_pipe); - if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) - return 0; + if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) { + ret = 0; + goto out; + } schedule(); } - return -ETIMEDOUT; + ret = -ETIMEDOUT; + +out: + dur = jiffies - started; + if (dur > HZ) + ath10k_dbg(ar, ATH10K_DBG_BMI, + "bmi cmd took %lu jiffies hz %d ret %d\n", + dur, HZ, ret); + return ret; } /* diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c new file mode 100644 index 000000000000..859ed870bd97 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -0,0 +1,2113 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc. + * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/module.h> +#include <linux/mmc/card.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sd.h> +#include <linux/bitfield.h> +#include "core.h" +#include "bmi.h" +#include "debug.h" +#include "hif.h" +#include "htc.h" +#include "targaddrs.h" +#include "trace.h" +#include "sdio.h" + +/* inlined helper functions */ + +static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio, + size_t len) +{ + return __ALIGN_MASK((len), ar_sdio->mbox_info.block_mask); +} + +static inline enum ath10k_htc_ep_id pipe_id_to_eid(u8 pipe_id) +{ + return (enum ath10k_htc_ep_id)pipe_id; +} + +static inline void ath10k_sdio_mbox_free_rx_pkt(struct ath10k_sdio_rx_data *pkt) +{ + dev_kfree_skb(pkt->skb); + pkt->skb = NULL; + pkt->alloc_len = 0; + pkt->act_len = 0; + pkt->trailer_only = false; +} + +static inline int ath10k_sdio_mbox_alloc_rx_pkt(struct ath10k_sdio_rx_data *pkt, + size_t act_len, size_t full_len, + bool part_of_bundle, + bool last_in_bundle) +{ + pkt->skb = dev_alloc_skb(full_len); + if (!pkt->skb) + return -ENOMEM; + + pkt->act_len = act_len; + pkt->alloc_len = full_len; + pkt->part_of_bundle = part_of_bundle; + pkt->last_in_bundle = last_in_bundle; + pkt->trailer_only = false; + + return 0; +} + +static inline bool is_trailer_only_msg(struct ath10k_sdio_rx_data *pkt) +{ + bool trailer_only = false; + struct ath10k_htc_hdr *htc_hdr = + (struct ath10k_htc_hdr *)pkt->skb->data; + u16 len = __le16_to_cpu(htc_hdr->len); + + if (len == htc_hdr->trailer_len) + trailer_only = true; + + return trailer_only; +} + +/* sdio/mmc functions */ + +static inline void ath10k_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw, + unsigned int address, + unsigned char val) +{ + *arg = FIELD_PREP(BIT(31), write) | + FIELD_PREP(BIT(27), raw) | + FIELD_PREP(BIT(26), 1) | + FIELD_PREP(GENMASK(25, 9), address) | + FIELD_PREP(BIT(8), 1) | + FIELD_PREP(GENMASK(7, 0), val); +} + +static int ath10k_sdio_func0_cmd52_wr_byte(struct mmc_card *card, + unsigned int address, + unsigned char byte) +{ + struct mmc_command io_cmd; + + memset(&io_cmd, 0, sizeof(io_cmd)); + ath10k_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + return mmc_wait_for_cmd(card->host, &io_cmd, 0); +} + +static int ath10k_sdio_func0_cmd52_rd_byte(struct mmc_card *card, + unsigned int address, + unsigned char *byte) +{ + struct mmc_command io_cmd; + int ret; + + memset(&io_cmd, 0, sizeof(io_cmd)); + ath10k_sdio_set_cmd52_arg(&io_cmd.arg, 0, 0, address, 0); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + ret = mmc_wait_for_cmd(card->host, &io_cmd, 0); + if (!ret) + *byte = io_cmd.resp[0]; + + return ret; +} + +static int ath10k_sdio_config(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + unsigned char byte, asyncintdelay = 2; + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio configuration\n"); + + sdio_claim_host(func); + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte(func->card, + SDIO_CCCR_DRIVE_STRENGTH, + &byte); + + byte &= ~ATH10K_SDIO_DRIVE_DTSX_MASK; + byte |= FIELD_PREP(ATH10K_SDIO_DRIVE_DTSX_MASK, + ATH10K_SDIO_DRIVE_DTSX_TYPE_D); + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + SDIO_CCCR_DRIVE_STRENGTH, + byte); + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte( + func->card, + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR, + &byte); + + byte |= (CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D); + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR, + byte); + if (ret) { + ath10k_warn(ar, "failed to enable driver strength: %d\n", ret); + goto out; + } + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_SDIO3, + &byte); + + byte |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_SDIO3; + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_SDIO3, + byte); + if (ret) { + ath10k_warn(ar, "failed to enable 4-bit async irq mode: %d\n", + ret); + goto out; + } + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte(func->card, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + &byte); + + byte &= ~CCCR_SDIO_ASYNC_INT_DELAY_MASK; + byte |= FIELD_PREP(CCCR_SDIO_ASYNC_INT_DELAY_MASK, asyncintdelay); + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + byte); + + /* give us some time to enable, in ms */ + func->enable_timeout = 100; + + ret = sdio_set_block_size(func, ar_sdio->mbox_info.block_size); + if (ret) { + ath10k_warn(ar, "failed to set sdio block size to %d: %d\n", + ar_sdio->mbox_info.block_size, ret); + goto out; + } + +out: + sdio_release_host(func); + return ret; +} + +static int ath10k_sdio_write32(struct ath10k *ar, u32 addr, u32 val) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + sdio_writel(func, val, addr, &ret); + if (ret) { + ath10k_warn(ar, "failed to write 0x%x to address 0x%x: %d\n", + val, addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio write32 addr 0x%x val 0x%x\n", + addr, val); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_writesb32(struct ath10k *ar, u32 addr, u32 val) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + __le32 *buf; + int ret; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + *buf = cpu_to_le32(val); + + sdio_claim_host(func); + + ret = sdio_writesb(func, addr, buf, sizeof(*buf)); + if (ret) { + ath10k_warn(ar, "failed to write value 0x%x to fixed sb address 0x%x: %d\n", + val, addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio writesb32 addr 0x%x val 0x%x\n", + addr, val); + +out: + sdio_release_host(func); + + kfree(buf); + + return ret; +} + +static int ath10k_sdio_read32(struct ath10k *ar, u32 addr, u32 *val) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + *val = sdio_readl(func, addr, &ret); + if (ret) { + ath10k_warn(ar, "failed to read from address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio read32 addr 0x%x val 0x%x\n", + addr, *val); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_read(struct ath10k *ar, u32 addr, void *buf, size_t len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + ret = sdio_memcpy_fromio(func, buf, addr, len); + if (ret) { + ath10k_warn(ar, "failed to read from address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio read addr 0x%x buf 0x%p len %zu\n", + addr, buf, len); + ath10k_dbg_dump(ar, ATH10K_DBG_SDIO_DUMP, NULL, "sdio read ", buf, len); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_write(struct ath10k *ar, u32 addr, const void *buf, size_t len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + /* For some reason toio() doesn't have const for the buffer, need + * an ugly hack to workaround that. + */ + ret = sdio_memcpy_toio(func, addr, (void *)buf, len); + if (ret) { + ath10k_warn(ar, "failed to write to address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio write addr 0x%x buf 0x%p len %zu\n", + addr, buf, len); + ath10k_dbg_dump(ar, ATH10K_DBG_SDIO_DUMP, NULL, "sdio write ", buf, len); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_readsb(struct ath10k *ar, u32 addr, void *buf, size_t len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + len = round_down(len, ar_sdio->mbox_info.block_size); + + ret = sdio_readsb(func, buf, addr, len); + if (ret) { + ath10k_warn(ar, "failed to read from fixed (sb) address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio readsb addr 0x%x buf 0x%p len %zu\n", + addr, buf, len); + ath10k_dbg_dump(ar, ATH10K_DBG_SDIO_DUMP, NULL, "sdio readsb ", buf, len); + +out: + sdio_release_host(func); + + return ret; +} + +/* HIF mbox functions */ + +static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar, + struct ath10k_sdio_rx_data *pkt, + u32 *lookaheads, + int *n_lookaheads) +{ + struct ath10k_htc *htc = &ar->htc; + struct sk_buff *skb = pkt->skb; + struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data; + bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; + enum ath10k_htc_ep_id eid; + u16 payload_len; + u8 *trailer; + int ret; + + payload_len = le16_to_cpu(htc_hdr->len); + + if (trailer_present) { + trailer = skb->data + sizeof(*htc_hdr) + + payload_len - htc_hdr->trailer_len; + + eid = pipe_id_to_eid(htc_hdr->eid); + + ret = ath10k_htc_process_trailer(htc, + trailer, + htc_hdr->trailer_len, + eid, + lookaheads, + n_lookaheads); + if (ret) + return ret; + + if (is_trailer_only_msg(pkt)) + pkt->trailer_only = true; + + skb_trim(skb, skb->len - htc_hdr->trailer_len); + } + + skb_pull(skb, sizeof(*htc_hdr)); + + return 0; +} + +static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar, + u32 lookaheads[], + int *n_lookahead) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_htc *htc = &ar->htc; + struct ath10k_sdio_rx_data *pkt; + struct ath10k_htc_ep *ep; + enum ath10k_htc_ep_id id; + int ret, i, *n_lookahead_local; + u32 *lookaheads_local; + + for (i = 0; i < ar_sdio->n_rx_pkts; i++) { + lookaheads_local = lookaheads; + n_lookahead_local = n_lookahead; + + id = ((struct ath10k_htc_hdr *)&lookaheads[i])->eid; + + if (id >= ATH10K_HTC_EP_COUNT) { + ath10k_warn(ar, "invalid endpoint in look-ahead: %d\n", + id); + ret = -ENOMEM; + goto out; + } + + ep = &htc->endpoint[id]; + + if (ep->service_id == 0) { + ath10k_warn(ar, "ep %d is not connected\n", id); + ret = -ENOMEM; + goto out; + } + + pkt = &ar_sdio->rx_pkts[i]; + + if (pkt->part_of_bundle && !pkt->last_in_bundle) { + /* Only read lookahead's from RX trailers + * for the last packet in a bundle. + */ + lookaheads_local = NULL; + n_lookahead_local = NULL; + } + + ret = ath10k_sdio_mbox_rx_process_packet(ar, + pkt, + lookaheads_local, + n_lookahead_local); + if (ret) + goto out; + + if (!pkt->trailer_only) + ep->ep_ops.ep_rx_complete(ar_sdio->ar, pkt->skb); + else + kfree_skb(pkt->skb); + + /* The RX complete handler now owns the skb...*/ + pkt->skb = NULL; + pkt->alloc_len = 0; + } + + ret = 0; + +out: + /* Free all packets that was not passed on to the RX completion + * handler... + */ + for (; i < ar_sdio->n_rx_pkts; i++) + ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]); + + return ret; +} + +static int ath10k_sdio_mbox_alloc_pkt_bundle(struct ath10k *ar, + struct ath10k_sdio_rx_data *rx_pkts, + struct ath10k_htc_hdr *htc_hdr, + size_t full_len, size_t act_len, + size_t *bndl_cnt) +{ + int ret, i; + + *bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr->flags); + + if (*bndl_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE) { + ath10k_warn(ar, + "HTC bundle length %u exceeds maximum %u\n", + le16_to_cpu(htc_hdr->len), + HTC_HOST_MAX_MSG_PER_BUNDLE); + return -ENOMEM; + } + + /* Allocate bndl_cnt extra skb's for the bundle. + * The package containing the + * ATH10K_HTC_FLAG_BUNDLE_MASK flag is not included + * in bndl_cnt. The skb for that packet will be + * allocated separately. + */ + for (i = 0; i < *bndl_cnt; i++) { + ret = ath10k_sdio_mbox_alloc_rx_pkt(&rx_pkts[i], + act_len, + full_len, + true, + false); + if (ret) + return ret; + } + + return 0; +} + +static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar, + u32 lookaheads[], int n_lookaheads) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_htc_hdr *htc_hdr; + size_t full_len, act_len; + bool last_in_bundle; + int ret, i; + + if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) { + ath10k_warn(ar, + "the total number of pkgs to be fetched (%u) exceeds maximum %u\n", + n_lookaheads, + ATH10K_SDIO_MAX_RX_MSGS); + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < n_lookaheads; i++) { + htc_hdr = (struct ath10k_htc_hdr *)&lookaheads[i]; + last_in_bundle = false; + + if (le16_to_cpu(htc_hdr->len) > + ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH) { + ath10k_warn(ar, + "payload length %d exceeds max htc length: %zu\n", + le16_to_cpu(htc_hdr->len), + ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH); + ret = -ENOMEM; + goto err; + } + + act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr); + full_len = ath10k_sdio_calc_txrx_padded_len(ar_sdio, act_len); + + if (full_len > ATH10K_SDIO_MAX_BUFFER_SIZE) { + ath10k_warn(ar, + "rx buffer requested with invalid htc_hdr length (%d, 0x%x): %d\n", + htc_hdr->eid, htc_hdr->flags, + le16_to_cpu(htc_hdr->len)); + ret = -EINVAL; + goto err; + } + + if (htc_hdr->flags & ATH10K_HTC_FLAG_BUNDLE_MASK) { + /* HTC header indicates that every packet to follow + * has the same padded length so that it can be + * optimally fetched as a full bundle. + */ + size_t bndl_cnt; + + ret = ath10k_sdio_mbox_alloc_pkt_bundle(ar, + &ar_sdio->rx_pkts[i], + htc_hdr, + full_len, + act_len, + &bndl_cnt); + + n_lookaheads += bndl_cnt; + i += bndl_cnt; + /*Next buffer will be the last in the bundle */ + last_in_bundle = true; + } + + /* Allocate skb for packet. If the packet had the + * ATH10K_HTC_FLAG_BUNDLE_MASK flag set, all bundled + * packet skb's have been allocated in the previous step. + */ + ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[i], + act_len, + full_len, + last_in_bundle, + last_in_bundle); + } + + ar_sdio->n_rx_pkts = i; + + return 0; + +err: + for (i = 0; i < ATH10K_SDIO_MAX_RX_MSGS; i++) { + if (!ar_sdio->rx_pkts[i].alloc_len) + break; + ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]); + } + + return ret; +} + +static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar, + struct ath10k_sdio_rx_data *pkt) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sk_buff *skb = pkt->skb; + int ret; + + ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr, + skb->data, pkt->alloc_len); + pkt->status = ret; + if (!ret) + skb_put(skb, pkt->act_len); + + return ret; +} + +static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + int ret, i; + + for (i = 0; i < ar_sdio->n_rx_pkts; i++) { + ret = ath10k_sdio_mbox_rx_packet(ar, + &ar_sdio->rx_pkts[i]); + if (ret) + goto err; + } + + return 0; + +err: + /* Free all packets that was not successfully fetched. */ + for (; i < ar_sdio->n_rx_pkts; i++) + ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]); + + return ret; +} + +/* This is the timeout for mailbox processing done in the sdio irq + * handler. The timeout is deliberately set quite high since SDIO dump logs + * over serial port can/will add a substantial overhead to the processing + * (if enabled). + */ +#define SDIO_MBOX_PROCESSING_TIMEOUT_HZ (20 * HZ) + +static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar, + u32 msg_lookahead, bool *done) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + u32 lookaheads[ATH10K_SDIO_MAX_RX_MSGS]; + int n_lookaheads = 1; + unsigned long timeout; + int ret; + + *done = true; + + /* Copy the lookahead obtained from the HTC register table into our + * temp array as a start value. + */ + lookaheads[0] = msg_lookahead; + + timeout = jiffies + SDIO_MBOX_PROCESSING_TIMEOUT_HZ; + while (time_before(jiffies, timeout)) { + /* Try to allocate as many HTC RX packets indicated by + * n_lookaheads. + */ + ret = ath10k_sdio_mbox_rx_alloc(ar, lookaheads, + n_lookaheads); + if (ret) + break; + + if (ar_sdio->n_rx_pkts >= 2) + /* A recv bundle was detected, force IRQ status + * re-check again. + */ + *done = false; + + ret = ath10k_sdio_mbox_rx_fetch(ar); + + /* Process fetched packets. This will potentially update + * n_lookaheads depending on if the packets contain lookahead + * reports. + */ + n_lookaheads = 0; + ret = ath10k_sdio_mbox_rx_process_packets(ar, + lookaheads, + &n_lookaheads); + + if (!n_lookaheads || ret) + break; + + /* For SYNCH processing, if we get here, we are running + * through the loop again due to updated lookaheads. Set + * flag that we should re-check IRQ status registers again + * before leaving IRQ processing, this can net better + * performance in high throughput situations. + */ + *done = false; + } + + if (ret && (ret != -ECANCELED)) + ath10k_warn(ar, "failed to get pending recv messages: %d\n", + ret); + + return ret; +} + +static int ath10k_sdio_mbox_proc_dbg_intr(struct ath10k *ar) +{ + u32 val; + int ret; + + /* TODO: Add firmware crash handling */ + ath10k_warn(ar, "firmware crashed\n"); + + /* read counter to clear the interrupt, the debug error interrupt is + * counter 0. + */ + ret = ath10k_sdio_read32(ar, MBOX_COUNT_DEC_ADDRESS, &val); + if (ret) + ath10k_warn(ar, "failed to clear debug interrupt: %d\n", ret); + + return ret; +} + +static int ath10k_sdio_mbox_proc_counter_intr(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + u8 counter_int_status; + int ret; + + mutex_lock(&irq_data->mtx); + counter_int_status = irq_data->irq_proc_reg->counter_int_status & + irq_data->irq_en_reg->cntr_int_status_en; + + /* NOTE: other modules like GMBOX may use the counter interrupt for + * credit flow control on other counters, we only need to check for + * the debug assertion counter interrupt. + */ + if (counter_int_status & ATH10K_SDIO_TARGET_DEBUG_INTR_MASK) + ret = ath10k_sdio_mbox_proc_dbg_intr(ar); + else + ret = 0; + + mutex_unlock(&irq_data->mtx); + + return ret; +} + +static int ath10k_sdio_mbox_proc_err_intr(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + u8 error_int_status; + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio error interrupt\n"); + + error_int_status = irq_data->irq_proc_reg->error_int_status & 0x0F; + if (!error_int_status) { + ath10k_warn(ar, "invalid error interrupt status: 0x%x\n", + error_int_status); + return -EIO; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio error_int_status 0x%x\n", error_int_status); + + if (FIELD_GET(MBOX_ERROR_INT_STATUS_WAKEUP_MASK, + error_int_status)) + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio interrupt error wakeup\n"); + + if (FIELD_GET(MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + error_int_status)) + ath10k_warn(ar, "rx underflow interrupt error\n"); + + if (FIELD_GET(MBOX_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + error_int_status)) + ath10k_warn(ar, "tx overflow interrupt error\n"); + + /* Clear the interrupt */ + irq_data->irq_proc_reg->error_int_status &= ~error_int_status; + + /* set W1C value to clear the interrupt, this hits the register first */ + ret = ath10k_sdio_writesb32(ar, MBOX_ERROR_INT_STATUS_ADDRESS, + error_int_status); + if (ret) { + ath10k_warn(ar, "unable to write to error int status address: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + u8 cpu_int_status; + int ret; + + mutex_lock(&irq_data->mtx); + cpu_int_status = irq_data->irq_proc_reg->cpu_int_status & + irq_data->irq_en_reg->cpu_int_status_en; + if (!cpu_int_status) { + ath10k_warn(ar, "CPU interrupt status is zero\n"); + ret = -EIO; + goto out; + } + + /* Clear the interrupt */ + irq_data->irq_proc_reg->cpu_int_status &= ~cpu_int_status; + + /* Set up the register transfer buffer to hit the register 4 times, + * this is done to make the access 4-byte aligned to mitigate issues + * with host bus interconnects that restrict bus transfer lengths to + * be a multiple of 4-bytes. + * + * Set W1C value to clear the interrupt, this hits the register first. + */ + ret = ath10k_sdio_writesb32(ar, MBOX_CPU_INT_STATUS_ADDRESS, + cpu_int_status); + if (ret) { + ath10k_warn(ar, "unable to write to cpu interrupt status address: %d\n", + ret); + goto out; + } + +out: + mutex_unlock(&irq_data->mtx); + return ret; +} + +static int ath10k_sdio_mbox_read_int_status(struct ath10k *ar, + u8 *host_int_status, + u32 *lookahead) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_proc_regs *irq_proc_reg = irq_data->irq_proc_reg; + struct ath10k_sdio_irq_enable_regs *irq_en_reg = irq_data->irq_en_reg; + u8 htc_mbox = FIELD_PREP(ATH10K_HTC_MAILBOX_MASK, 1); + int ret; + + mutex_lock(&irq_data->mtx); + + *lookahead = 0; + *host_int_status = 0; + + /* int_status_en is supposed to be non zero, otherwise interrupts + * shouldn't be enabled. There is however a short time frame during + * initialization between the irq register and int_status_en init + * where this can happen. + * We silently ignore this condition. + */ + if (!irq_en_reg->int_status_en) { + ret = 0; + goto out; + } + + /* Read the first sizeof(struct ath10k_irq_proc_registers) + * bytes of the HTC register table. This + * will yield us the value of different int status + * registers and the lookahead registers. + */ + ret = ath10k_sdio_read(ar, MBOX_HOST_INT_STATUS_ADDRESS, + irq_proc_reg, sizeof(*irq_proc_reg)); + if (ret) + goto out; + + /* Update only those registers that are enabled */ + *host_int_status = irq_proc_reg->host_int_status & + irq_en_reg->int_status_en; + + /* Look at mbox status */ + if (!(*host_int_status & htc_mbox)) { + *lookahead = 0; + ret = 0; + goto out; + } + + /* Mask out pending mbox value, we use look ahead as + * the real flag for mbox processing. + */ + *host_int_status &= ~htc_mbox; + if (irq_proc_reg->rx_lookahead_valid & htc_mbox) { + *lookahead = le32_to_cpu( + irq_proc_reg->rx_lookahead[ATH10K_HTC_MAILBOX]); + if (!*lookahead) + ath10k_warn(ar, "sdio mbox lookahead is zero\n"); + } + +out: + mutex_unlock(&irq_data->mtx); + return ret; +} + +static int ath10k_sdio_mbox_proc_pending_irqs(struct ath10k *ar, + bool *done) +{ + u8 host_int_status; + u32 lookahead; + int ret; + + /* NOTE: HIF implementation guarantees that the context of this + * call allows us to perform SYNCHRONOUS I/O, that is we can block, + * sleep or call any API that can block or switch thread/task + * contexts. This is a fully schedulable context. + */ + + ret = ath10k_sdio_mbox_read_int_status(ar, + &host_int_status, + &lookahead); + if (ret) { + *done = true; + goto out; + } + + if (!host_int_status && !lookahead) { + ret = 0; + *done = true; + goto out; + } + + if (lookahead) { + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio pending mailbox msg lookahead 0x%08x\n", + lookahead); + + ret = ath10k_sdio_mbox_rxmsg_pending_handler(ar, + lookahead, + done); + if (ret) + goto out; + } + + /* now, handle the rest of the interrupts */ + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio host_int_status 0x%x\n", host_int_status); + + if (FIELD_GET(MBOX_HOST_INT_STATUS_CPU_MASK, host_int_status)) { + /* CPU Interrupt */ + ret = ath10k_sdio_mbox_proc_cpu_intr(ar); + if (ret) + goto out; + } + + if (FIELD_GET(MBOX_HOST_INT_STATUS_ERROR_MASK, host_int_status)) { + /* Error Interrupt */ + ret = ath10k_sdio_mbox_proc_err_intr(ar); + if (ret) + goto out; + } + + if (FIELD_GET(MBOX_HOST_INT_STATUS_COUNTER_MASK, host_int_status)) + /* Counter Interrupt */ + ret = ath10k_sdio_mbox_proc_counter_intr(ar); + + ret = 0; + +out: + /* An optimization to bypass reading the IRQ status registers + * unecessarily which can re-wake the target, if upper layers + * determine that we are in a low-throughput mode, we can rely on + * taking another interrupt rather than re-checking the status + * registers which can re-wake the target. + * + * NOTE : for host interfaces that makes use of detecting pending + * mbox messages at hif can not use this optimization due to + * possible side effects, SPI requires the host to drain all + * messages from the mailbox before exiting the ISR routine. + */ + + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio pending irqs done %d status %d", + *done, ret); + + return ret; +} + +static void ath10k_sdio_set_mbox_info(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_mbox_info *mbox_info = &ar_sdio->mbox_info; + u16 device = ar_sdio->func->device, dev_id_base, dev_id_chiprev; + + mbox_info->htc_addr = ATH10K_HIF_MBOX_BASE_ADDR; + mbox_info->block_size = ATH10K_HIF_MBOX_BLOCK_SIZE; + mbox_info->block_mask = ATH10K_HIF_MBOX_BLOCK_SIZE - 1; + mbox_info->gmbox_addr = ATH10K_HIF_GMBOX_BASE_ADDR; + mbox_info->gmbox_sz = ATH10K_HIF_GMBOX_WIDTH; + + mbox_info->ext_info[0].htc_ext_addr = ATH10K_HIF_MBOX0_EXT_BASE_ADDR; + + dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, device); + dev_id_chiprev = FIELD_GET(QCA_MANUFACTURER_ID_REV_MASK, device); + switch (dev_id_base) { + case QCA_MANUFACTURER_ID_AR6005_BASE: + if (dev_id_chiprev < 4) + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH; + else + /* from QCA6174 2.0(0x504), the width has been extended + * to 56K + */ + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0; + break; + case QCA_MANUFACTURER_ID_QCA9377_BASE: + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0; + break; + default: + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH; + } + + mbox_info->ext_info[1].htc_ext_addr = + mbox_info->ext_info[0].htc_ext_addr + + mbox_info->ext_info[0].htc_ext_sz + + ATH10K_HIF_MBOX_DUMMY_SPACE_SIZE; + mbox_info->ext_info[1].htc_ext_sz = ATH10K_HIF_MBOX1_EXT_WIDTH; +} + +/* BMI functions */ + +static int ath10k_sdio_bmi_credits(struct ath10k *ar) +{ + u32 addr, cmd_credits; + unsigned long timeout; + int ret; + + /* Read the counter register to get the command credits */ + addr = MBOX_COUNT_DEC_ADDRESS + ATH10K_HIF_MBOX_NUM_MAX * 4; + timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + cmd_credits = 0; + + while (time_before(jiffies, timeout) && !cmd_credits) { + /* Hit the credit counter with a 4-byte access, the first byte + * read will hit the counter and cause a decrement, while the + * remaining 3 bytes has no effect. The rationale behind this + * is to make all HIF accesses 4-byte aligned. + */ + ret = ath10k_sdio_read32(ar, addr, &cmd_credits); + if (ret) { + ath10k_warn(ar, + "unable to decrement the command credit count register: %d\n", + ret); + return ret; + } + + /* The counter is only 8 bits. + * Ignore anything in the upper 3 bytes + */ + cmd_credits &= 0xFF; + } + + if (!cmd_credits) { + ath10k_warn(ar, "bmi communication timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int ath10k_sdio_bmi_get_rx_lookahead(struct ath10k *ar) +{ + unsigned long timeout; + u32 rx_word; + int ret; + + timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + rx_word = 0; + + while ((time_before(jiffies, timeout)) && !rx_word) { + ret = ath10k_sdio_read32(ar, + MBOX_HOST_INT_STATUS_ADDRESS, + &rx_word); + if (ret) { + ath10k_warn(ar, "unable to read RX_LOOKAHEAD_VALID: %d\n", ret); + return ret; + } + + /* all we really want is one bit */ + rx_word &= 1; + } + + if (!rx_word) { + ath10k_warn(ar, "bmi_recv_buf FIFO empty\n"); + return -EINVAL; + } + + return ret; +} + +static int ath10k_sdio_bmi_exchange_msg(struct ath10k *ar, + void *req, u32 req_len, + void *resp, u32 *resp_len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + u32 addr; + int ret; + + if (req) { + ret = ath10k_sdio_bmi_credits(ar); + if (ret) + return ret; + + addr = ar_sdio->mbox_info.htc_addr; + + memcpy(ar_sdio->bmi_buf, req, req_len); + ret = ath10k_sdio_write(ar, addr, ar_sdio->bmi_buf, req_len); + if (ret) { + ath10k_warn(ar, + "unable to send the bmi data to the device: %d\n", + ret); + return ret; + } + } + + if (!resp || !resp_len) + /* No response expected */ + return 0; + + /* During normal bootup, small reads may be required. + * Rather than issue an HIF Read and then wait as the Target + * adds successive bytes to the FIFO, we wait here until + * we know that response data is available. + * + * This allows us to cleanly timeout on an unexpected + * Target failure rather than risk problems at the HIF level. + * In particular, this avoids SDIO timeouts and possibly garbage + * data on some host controllers. And on an interconnect + * such as Compact Flash (as well as some SDIO masters) which + * does not provide any indication on data timeout, it avoids + * a potential hang or garbage response. + * + * Synchronization is more difficult for reads larger than the + * size of the MBOX FIFO (128B), because the Target is unable + * to push the 129th byte of data until AFTER the Host posts an + * HIF Read and removes some FIFO data. So for large reads the + * Host proceeds to post an HIF Read BEFORE all the data is + * actually available to read. Fortunately, large BMI reads do + * not occur in practice -- they're supported for debug/development. + * + * So Host/Target BMI synchronization is divided into these cases: + * CASE 1: length < 4 + * Should not happen + * + * CASE 2: 4 <= length <= 128 + * Wait for first 4 bytes to be in FIFO + * If CONSERVATIVE_BMI_READ is enabled, also wait for + * a BMI command credit, which indicates that the ENTIRE + * response is available in the the FIFO + * + * CASE 3: length > 128 + * Wait for the first 4 bytes to be in FIFO + * + * For most uses, a small timeout should be sufficient and we will + * usually see a response quickly; but there may be some unusual + * (debug) cases of BMI_EXECUTE where we want an larger timeout. + * For now, we use an unbounded busy loop while waiting for + * BMI_EXECUTE. + * + * If BMI_EXECUTE ever needs to support longer-latency execution, + * especially in production, this code needs to be enhanced to sleep + * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently + * a function of Host processor speed. + */ + ret = ath10k_sdio_bmi_get_rx_lookahead(ar); + if (ret) + return ret; + + /* We always read from the start of the mbox address */ + addr = ar_sdio->mbox_info.htc_addr; + ret = ath10k_sdio_read(ar, addr, ar_sdio->bmi_buf, *resp_len); + if (ret) { + ath10k_warn(ar, + "unable to read the bmi data from the device: %d\n", + ret); + return ret; + } + + memcpy(resp, ar_sdio->bmi_buf, *resp_len); + + return 0; +} + +/* sdio async handling functions */ + +static struct ath10k_sdio_bus_request +*ath10k_sdio_alloc_busreq(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_bus_request *bus_req; + + spin_lock_bh(&ar_sdio->lock); + + if (list_empty(&ar_sdio->bus_req_freeq)) { + bus_req = NULL; + goto out; + } + + bus_req = list_first_entry(&ar_sdio->bus_req_freeq, + struct ath10k_sdio_bus_request, list); + list_del(&bus_req->list); + +out: + spin_unlock_bh(&ar_sdio->lock); + return bus_req; +} + +static void ath10k_sdio_free_bus_req(struct ath10k *ar, + struct ath10k_sdio_bus_request *bus_req) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + + memset(bus_req, 0, sizeof(*bus_req)); + + spin_lock_bh(&ar_sdio->lock); + list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); + spin_unlock_bh(&ar_sdio->lock); +} + +static void __ath10k_sdio_write_async(struct ath10k *ar, + struct ath10k_sdio_bus_request *req) +{ + struct ath10k_htc_ep *ep; + struct sk_buff *skb; + int ret; + + skb = req->skb; + ret = ath10k_sdio_write(ar, req->address, skb->data, skb->len); + if (ret) + ath10k_warn(ar, "failed to write skb to 0x%x asynchronously: %d", + req->address, ret); + + if (req->htc_msg) { + ep = &ar->htc.endpoint[req->eid]; + ath10k_htc_notify_tx_completion(ep, skb); + } else if (req->comp) { + complete(req->comp); + } + + ath10k_sdio_free_bus_req(ar, req); +} + +static void ath10k_sdio_write_async_work(struct work_struct *work) +{ + struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio, + wr_async_work); + struct ath10k *ar = ar_sdio->ar; + struct ath10k_sdio_bus_request *req, *tmp_req; + + spin_lock_bh(&ar_sdio->wr_async_lock); + + list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { + list_del(&req->list); + spin_unlock_bh(&ar_sdio->wr_async_lock); + __ath10k_sdio_write_async(ar, req); + spin_lock_bh(&ar_sdio->wr_async_lock); + } + + spin_unlock_bh(&ar_sdio->wr_async_lock); +} + +static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr, + struct sk_buff *skb, + struct completion *comp, + bool htc_msg, enum ath10k_htc_ep_id eid) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_bus_request *bus_req; + + /* Allocate a bus request for the message and queue it on the + * SDIO workqueue. + */ + bus_req = ath10k_sdio_alloc_busreq(ar); + if (!bus_req) { + ath10k_warn(ar, + "unable to allocate bus request for async request\n"); + return -ENOMEM; + } + + bus_req->skb = skb; + bus_req->eid = eid; + bus_req->address = addr; + bus_req->htc_msg = htc_msg; + bus_req->comp = comp; + + spin_lock_bh(&ar_sdio->wr_async_lock); + list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq); + spin_unlock_bh(&ar_sdio->wr_async_lock); + + return 0; +} + +/* IRQ handler */ + +static void ath10k_sdio_irq_handler(struct sdio_func *func) +{ + struct ath10k_sdio *ar_sdio = sdio_get_drvdata(func); + struct ath10k *ar = ar_sdio->ar; + unsigned long timeout; + bool done = false; + int ret; + + /* Release the host during interrupts so we can pick it back up when + * we process commands. + */ + sdio_release_host(ar_sdio->func); + + timeout = jiffies + ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ; + while (time_before(jiffies, timeout) && !done) { + ret = ath10k_sdio_mbox_proc_pending_irqs(ar, &done); + if (ret) + break; + } + + sdio_claim_host(ar_sdio->func); + + wake_up(&ar_sdio->irq_wq); + + if (ret && ret != -ECANCELED) + ath10k_warn(ar, "failed to process pending SDIO interrupts: %d\n", + ret); +} + +/* sdio HIF functions */ + +static int ath10k_sdio_hif_disable_intrs(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_enable_regs *regs = irq_data->irq_en_reg; + int ret; + + mutex_lock(&irq_data->mtx); + + memset(regs, 0, sizeof(*regs)); + ret = ath10k_sdio_write(ar, MBOX_INT_STATUS_ENABLE_ADDRESS, + ®s->int_status_en, sizeof(*regs)); + if (ret) + ath10k_warn(ar, "unable to disable sdio interrupts: %d\n", ret); + + mutex_unlock(&irq_data->mtx); + + return ret; +} + +static int ath10k_sdio_hif_power_up(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + if (!ar_sdio->is_disabled) + return 0; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio power on\n"); + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) { + ath10k_warn(ar, "unable to enable sdio function: %d)\n", ret); + sdio_release_host(func); + return ret; + } + + sdio_release_host(func); + + /* Wait for hardware to initialise. It should take a lot less than + * 20 ms but let's be conservative here. + */ + msleep(20); + + ar_sdio->is_disabled = false; + + ret = ath10k_sdio_hif_disable_intrs(ar); + if (ret) + return ret; + + return 0; +} + +static void ath10k_sdio_hif_power_down(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + int ret; + + if (ar_sdio->is_disabled) + return; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio power off\n"); + + /* Disable the card */ + sdio_claim_host(ar_sdio->func); + ret = sdio_disable_func(ar_sdio->func); + sdio_release_host(ar_sdio->func); + + if (ret) + ath10k_warn(ar, "unable to disable sdio function: %d\n", ret); + + ar_sdio->is_disabled = true; +} + +static int ath10k_sdio_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + enum ath10k_htc_ep_id eid; + struct sk_buff *skb; + int ret, i; + + eid = pipe_id_to_eid(pipe_id); + + for (i = 0; i < n_items; i++) { + size_t padded_len; + u32 address; + + skb = items[i].transfer_context; + padded_len = ath10k_sdio_calc_txrx_padded_len(ar_sdio, + skb->len); + skb_trim(skb, padded_len); + + /* Write TX data to the end of the mbox address space */ + address = ar_sdio->mbox_addr[eid] + ar_sdio->mbox_size[eid] - + skb->len; + ret = ath10k_sdio_prep_async_req(ar, address, skb, + NULL, true, eid); + if (ret) + return ret; + } + + queue_work(ar_sdio->workqueue, &ar_sdio->wr_async_work); + + return 0; +} + +static int ath10k_sdio_hif_enable_intrs(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_enable_regs *regs = irq_data->irq_en_reg; + int ret; + + mutex_lock(&irq_data->mtx); + + /* Enable all but CPU interrupts */ + regs->int_status_en = FIELD_PREP(MBOX_INT_STATUS_ENABLE_ERROR_MASK, 1) | + FIELD_PREP(MBOX_INT_STATUS_ENABLE_CPU_MASK, 1) | + FIELD_PREP(MBOX_INT_STATUS_ENABLE_COUNTER_MASK, 1); + + /* NOTE: There are some cases where HIF can do detection of + * pending mbox messages which is disabled now. + */ + regs->int_status_en |= + FIELD_PREP(MBOX_INT_STATUS_ENABLE_MBOX_DATA_MASK, 1); + + /* Set up the CPU Interrupt status Register */ + regs->cpu_int_status_en = 0; + + /* Set up the Error Interrupt status Register */ + regs->err_int_status_en = + FIELD_PREP(MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, 1) | + FIELD_PREP(MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, 1); + + /* Enable Counter interrupt status register to get fatal errors for + * debugging. + */ + regs->cntr_int_status_en = + FIELD_PREP(MBOX_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + ATH10K_SDIO_TARGET_DEBUG_INTR_MASK); + + ret = ath10k_sdio_write(ar, MBOX_INT_STATUS_ENABLE_ADDRESS, + ®s->int_status_en, sizeof(*regs)); + if (ret) + ath10k_warn(ar, + "failed to update mbox interrupt status register : %d\n", + ret); + + mutex_unlock(&irq_data->mtx); + return ret; +} + +static int ath10k_sdio_hif_set_mbox_sleep(struct ath10k *ar, bool enable_sleep) +{ + u32 val; + int ret; + + ret = ath10k_sdio_read32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, &val); + if (ret) { + ath10k_warn(ar, "failed to read fifo/chip control register: %d\n", + ret); + return ret; + } + + if (enable_sleep) + val &= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF; + else + val |= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON; + + ret = ath10k_sdio_write32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, val); + if (ret) { + ath10k_warn(ar, "failed to write to FIFO_TIMEOUT_AND_CHIP_CONTROL: %d", + ret); + return ret; + } + + return 0; +} + +/* HIF diagnostics */ + +static int ath10k_sdio_hif_diag_read(struct ath10k *ar, u32 address, void *buf, + size_t buf_len) +{ + int ret; + + /* set window register to start read cycle */ + ret = ath10k_sdio_write32(ar, MBOX_WINDOW_READ_ADDR_ADDRESS, address); + if (ret) { + ath10k_warn(ar, "failed to set mbox window read address: %d", ret); + return ret; + } + + /* read the data */ + ret = ath10k_sdio_read(ar, MBOX_WINDOW_DATA_ADDRESS, buf, buf_len); + if (ret) { + ath10k_warn(ar, "failed to read from mbox window data address: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath10k_sdio_hif_diag_read32(struct ath10k *ar, u32 address, + u32 *value) +{ + __le32 *val; + int ret; + + val = kzalloc(sizeof(*val), GFP_KERNEL); + if (!val) + return -ENOMEM; + + ret = ath10k_sdio_hif_diag_read(ar, address, val, sizeof(*val)); + if (ret) + goto out; + + *value = __le32_to_cpu(*val); + +out: + kfree(val); + + return ret; +} + +static int ath10k_sdio_hif_diag_write_mem(struct ath10k *ar, u32 address, + const void *data, int nbytes) +{ + int ret; + + /* set write data */ + ret = ath10k_sdio_write(ar, MBOX_WINDOW_DATA_ADDRESS, data, nbytes); + if (ret) { + ath10k_warn(ar, + "failed to write 0x%p to mbox window data address: %d\n", + data, ret); + return ret; + } + + /* set window register, which starts the write cycle */ + ret = ath10k_sdio_write32(ar, MBOX_WINDOW_WRITE_ADDR_ADDRESS, address); + if (ret) { + ath10k_warn(ar, "failed to set mbox window write address: %d", ret); + return ret; + } + + return 0; +} + +/* HIF start/stop */ + +static int ath10k_sdio_hif_start(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + u32 addr, val; + int ret; + + /* Sleep 20 ms before HIF interrupts are disabled. + * This will give target plenty of time to process the BMI done + * request before interrupts are disabled. + */ + msleep(20); + ret = ath10k_sdio_hif_disable_intrs(ar); + if (ret) + return ret; + + /* eid 0 always uses the lower part of the extended mailbox address + * space (ext_info[0].htc_ext_addr). + */ + ar_sdio->mbox_addr[0] = ar_sdio->mbox_info.ext_info[0].htc_ext_addr; + ar_sdio->mbox_size[0] = ar_sdio->mbox_info.ext_info[0].htc_ext_sz; + + sdio_claim_host(ar_sdio->func); + + /* Register the isr */ + ret = sdio_claim_irq(ar_sdio->func, ath10k_sdio_irq_handler); + if (ret) { + ath10k_warn(ar, "failed to claim sdio interrupt: %d\n", ret); + sdio_release_host(ar_sdio->func); + return ret; + } + + sdio_release_host(ar_sdio->func); + + ret = ath10k_sdio_hif_enable_intrs(ar); + if (ret) + ath10k_warn(ar, "failed to enable sdio interrupts: %d\n", ret); + + addr = host_interest_item_address(HI_ITEM(hi_acs_flags)); + + ret = ath10k_sdio_hif_diag_read32(ar, addr, &val); + if (ret) { + ath10k_warn(ar, "unable to read hi_acs_flags address: %d\n", ret); + return ret; + } + + if (val & HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK) { + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio mailbox swap service enabled\n"); + ar_sdio->swap_mbox = true; + } + + /* Enable sleep and then disable it again */ + ret = ath10k_sdio_hif_set_mbox_sleep(ar, true); + if (ret) + return ret; + + /* Wait for 20ms for the written value to take effect */ + msleep(20); + + ret = ath10k_sdio_hif_set_mbox_sleep(ar, false); + if (ret) + return ret; + + return 0; +} + +#define SDIO_IRQ_DISABLE_TIMEOUT_HZ (3 * HZ) + +static void ath10k_sdio_irq_disable(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_enable_regs *regs = irq_data->irq_en_reg; + struct sk_buff *skb; + struct completion irqs_disabled_comp; + int ret; + + skb = dev_alloc_skb(sizeof(*regs)); + if (!skb) + return; + + mutex_lock(&irq_data->mtx); + + memset(regs, 0, sizeof(*regs)); /* disable all interrupts */ + memcpy(skb->data, regs, sizeof(*regs)); + skb_put(skb, sizeof(*regs)); + + mutex_unlock(&irq_data->mtx); + + init_completion(&irqs_disabled_comp); + ret = ath10k_sdio_prep_async_req(ar, MBOX_INT_STATUS_ENABLE_ADDRESS, + skb, &irqs_disabled_comp, false, 0); + if (ret) + goto out; + + queue_work(ar_sdio->workqueue, &ar_sdio->wr_async_work); + + /* Wait for the completion of the IRQ disable request. + * If there is a timeout we will try to disable irq's anyway. + */ + ret = wait_for_completion_timeout(&irqs_disabled_comp, + SDIO_IRQ_DISABLE_TIMEOUT_HZ); + if (!ret) + ath10k_warn(ar, "sdio irq disable request timed out\n"); + + sdio_claim_host(ar_sdio->func); + + ret = sdio_release_irq(ar_sdio->func); + if (ret) + ath10k_warn(ar, "failed to release sdio interrupt: %d\n", ret); + + sdio_release_host(ar_sdio->func); + +out: + kfree_skb(skb); +} + +static void ath10k_sdio_hif_stop(struct ath10k *ar) +{ + struct ath10k_sdio_bus_request *req, *tmp_req; + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + + ath10k_sdio_irq_disable(ar); + + cancel_work_sync(&ar_sdio->wr_async_work); + + spin_lock_bh(&ar_sdio->wr_async_lock); + + /* Free all bus requests that have not been handled */ + list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { + struct ath10k_htc_ep *ep; + + list_del(&req->list); + + if (req->htc_msg) { + ep = &ar->htc.endpoint[req->eid]; + ath10k_htc_notify_tx_completion(ep, req->skb); + } else if (req->skb) { + kfree_skb(req->skb); + } + ath10k_sdio_free_bus_req(ar, req); + } + + spin_unlock_bh(&ar_sdio->wr_async_lock); +} + +#ifdef CONFIG_PM + +static int ath10k_sdio_hif_suspend(struct ath10k *ar) +{ + return -EOPNOTSUPP; +} + +static int ath10k_sdio_hif_resume(struct ath10k *ar) +{ + switch (ar->state) { + case ATH10K_STATE_OFF: + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio resume configuring sdio\n"); + + /* need to set sdio settings after power is cut from sdio */ + ath10k_sdio_config(ar); + break; + + case ATH10K_STATE_ON: + default: + break; + } + + return 0; +} +#endif + +static int ath10k_sdio_hif_map_service_to_pipe(struct ath10k *ar, + u16 service_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_htc *htc = &ar->htc; + u32 htt_addr, wmi_addr, htt_mbox_size, wmi_mbox_size; + enum ath10k_htc_ep_id eid; + bool ep_found = false; + int i; + + /* For sdio, we are interested in the mapping between eid + * and pipeid rather than service_id to pipe_id. + * First we find out which eid has been allocated to the + * service... + */ + for (i = 0; i < ATH10K_HTC_EP_COUNT; i++) { + if (htc->endpoint[i].service_id == service_id) { + eid = htc->endpoint[i].eid; + ep_found = true; + break; + } + } + + if (!ep_found) + return -EINVAL; + + /* Then we create the simplest mapping possible between pipeid + * and eid + */ + *ul_pipe = *dl_pipe = (u8)eid; + + /* Normally, HTT will use the upper part of the extended + * mailbox address space (ext_info[1].htc_ext_addr) and WMI ctrl + * the lower part (ext_info[0].htc_ext_addr). + * If fw wants swapping of mailbox addresses, the opposite is true. + */ + if (ar_sdio->swap_mbox) { + htt_addr = ar_sdio->mbox_info.ext_info[0].htc_ext_addr; + wmi_addr = ar_sdio->mbox_info.ext_info[1].htc_ext_addr; + htt_mbox_size = ar_sdio->mbox_info.ext_info[0].htc_ext_sz; + wmi_mbox_size = ar_sdio->mbox_info.ext_info[1].htc_ext_sz; + } else { + htt_addr = ar_sdio->mbox_info.ext_info[1].htc_ext_addr; + wmi_addr = ar_sdio->mbox_info.ext_info[0].htc_ext_addr; + htt_mbox_size = ar_sdio->mbox_info.ext_info[1].htc_ext_sz; + wmi_mbox_size = ar_sdio->mbox_info.ext_info[0].htc_ext_sz; + } + + switch (service_id) { + case ATH10K_HTC_SVC_ID_RSVD_CTRL: + /* HTC ctrl ep mbox address has already been setup in + * ath10k_sdio_hif_start + */ + break; + case ATH10K_HTC_SVC_ID_WMI_CONTROL: + ar_sdio->mbox_addr[eid] = wmi_addr; + ar_sdio->mbox_size[eid] = wmi_mbox_size; + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio wmi ctrl mbox_addr 0x%x mbox_size %d\n", + ar_sdio->mbox_addr[eid], ar_sdio->mbox_size[eid]); + break; + case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: + ar_sdio->mbox_addr[eid] = htt_addr; + ar_sdio->mbox_size[eid] = htt_mbox_size; + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio htt data mbox_addr 0x%x mbox_size %d\n", + ar_sdio->mbox_addr[eid], ar_sdio->mbox_size[eid]); + break; + default: + ath10k_warn(ar, "unsupported HTC service id: %d\n", + service_id); + return -EINVAL; + } + + return 0; +} + +static void ath10k_sdio_hif_get_default_pipe(struct ath10k *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio hif get default pipe\n"); + + /* HTC ctrl ep (SVC id 1) always has eid (and pipe_id in our + * case) == 0 + */ + *ul_pipe = 0; + *dl_pipe = 0; +} + +/* This op is currently only used by htc_wait_target if the HTC ready + * message times out. It is not applicable for SDIO since there is nothing + * we can do if the HTC ready message does not arrive in time. + * TODO: Make this op non mandatory by introducing a NULL check in the + * hif op wrapper. + */ +static void ath10k_sdio_hif_send_complete_check(struct ath10k *ar, + u8 pipe, int force) +{ +} + +static const struct ath10k_hif_ops ath10k_sdio_hif_ops = { + .tx_sg = ath10k_sdio_hif_tx_sg, + .diag_read = ath10k_sdio_hif_diag_read, + .diag_write = ath10k_sdio_hif_diag_write_mem, + .exchange_bmi_msg = ath10k_sdio_bmi_exchange_msg, + .start = ath10k_sdio_hif_start, + .stop = ath10k_sdio_hif_stop, + .map_service_to_pipe = ath10k_sdio_hif_map_service_to_pipe, + .get_default_pipe = ath10k_sdio_hif_get_default_pipe, + .send_complete_check = ath10k_sdio_hif_send_complete_check, + .power_up = ath10k_sdio_hif_power_up, + .power_down = ath10k_sdio_hif_power_down, +#ifdef CONFIG_PM + .suspend = ath10k_sdio_hif_suspend, + .resume = ath10k_sdio_hif_resume, +#endif +}; + +#ifdef CONFIG_PM_SLEEP + +/* Empty handlers so that mmc subsystem doesn't remove us entirely during + * suspend. We instead follow cfg80211 suspend/resume handlers. + */ +static int ath10k_sdio_pm_suspend(struct device *device) +{ + return 0; +} + +static int ath10k_sdio_pm_resume(struct device *device) +{ + return 0; +} + +static SIMPLE_DEV_PM_OPS(ath10k_sdio_pm_ops, ath10k_sdio_pm_suspend, + ath10k_sdio_pm_resume); + +#define ATH10K_SDIO_PM_OPS (&ath10k_sdio_pm_ops) + +#else + +#define ATH10K_SDIO_PM_OPS NULL + +#endif /* CONFIG_PM_SLEEP */ + +static int ath10k_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct ath10k_sdio *ar_sdio; + struct ath10k *ar; + enum ath10k_hw_rev hw_rev; + u32 chip_id, dev_id_base; + int ret, i; + + /* Assumption: All SDIO based chipsets (so far) are QCA6174 based. + * If there will be newer chipsets that does not use the hw reg + * setup as defined in qca6174_regs and qca6174_values, this + * assumption is no longer valid and hw_rev must be setup differently + * depending on chipset. + */ + hw_rev = ATH10K_HW_QCA6174; + + ar = ath10k_core_create(sizeof(*ar_sdio), &func->dev, ATH10K_BUS_SDIO, + hw_rev, &ath10k_sdio_hif_ops); + if (!ar) { + dev_err(&func->dev, "failed to allocate core\n"); + return -ENOMEM; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n", + func->num, func->vendor, func->device, + func->max_blksize, func->cur_blksize); + + ar_sdio = ath10k_sdio_priv(ar); + + ar_sdio->irq_data.irq_proc_reg = + kzalloc(sizeof(struct ath10k_sdio_irq_proc_regs), + GFP_KERNEL); + if (!ar_sdio->irq_data.irq_proc_reg) { + ret = -ENOMEM; + goto err_core_destroy; + } + + ar_sdio->irq_data.irq_en_reg = + kzalloc(sizeof(struct ath10k_sdio_irq_enable_regs), + GFP_KERNEL); + if (!ar_sdio->irq_data.irq_en_reg) { + ret = -ENOMEM; + goto err_free_proc_reg; + } + + ar_sdio->bmi_buf = kzalloc(BMI_MAX_CMDBUF_SIZE, GFP_KERNEL); + if (!ar_sdio->bmi_buf) { + ret = -ENOMEM; + goto err_free_en_reg; + } + + ar_sdio->func = func; + sdio_set_drvdata(func, ar_sdio); + + ar_sdio->is_disabled = true; + ar_sdio->ar = ar; + + spin_lock_init(&ar_sdio->lock); + spin_lock_init(&ar_sdio->wr_async_lock); + mutex_init(&ar_sdio->irq_data.mtx); + + INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); + INIT_LIST_HEAD(&ar_sdio->wr_asyncq); + + INIT_WORK(&ar_sdio->wr_async_work, ath10k_sdio_write_async_work); + ar_sdio->workqueue = create_singlethread_workqueue("ath10k_sdio_wq"); + if (!ar_sdio->workqueue) { + ret = -ENOMEM; + goto err_free_bmi_buf; + } + + init_waitqueue_head(&ar_sdio->irq_wq); + + for (i = 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++) + ath10k_sdio_free_bus_req(ar, &ar_sdio->bus_req[i]); + + dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, id->device); + switch (dev_id_base) { + case QCA_MANUFACTURER_ID_AR6005_BASE: + case QCA_MANUFACTURER_ID_QCA9377_BASE: + ar->dev_id = QCA9377_1_0_DEVICE_ID; + break; + default: + ret = -ENODEV; + ath10k_err(ar, "unsupported device id %u (0x%x)\n", + dev_id_base, id->device); + goto err_free_bmi_buf; + } + + ar->id.vendor = id->vendor; + ar->id.device = id->device; + + ath10k_sdio_set_mbox_info(ar); + + ret = ath10k_sdio_config(ar); + if (ret) { + ath10k_err(ar, "failed to config sdio: %d\n", ret); + goto err_free_wq; + } + + /* TODO: don't know yet how to get chip_id with SDIO */ + chip_id = 0; + ret = ath10k_core_register(ar, chip_id); + if (ret) { + ath10k_err(ar, "failed to register driver core: %d\n", ret); + goto err_free_wq; + } + + /* TODO: remove this once SDIO support is fully implemented */ + ath10k_warn(ar, "WARNING: ath10k SDIO support is incomplete, don't expect anything to work!\n"); + + return 0; + +err_free_wq: + destroy_workqueue(ar_sdio->workqueue); +err_free_bmi_buf: + kfree(ar_sdio->bmi_buf); +err_free_en_reg: + kfree(ar_sdio->irq_data.irq_en_reg); +err_free_proc_reg: + kfree(ar_sdio->irq_data.irq_proc_reg); +err_core_destroy: + ath10k_core_destroy(ar); + + return ret; +} + +static void ath10k_sdio_remove(struct sdio_func *func) +{ + struct ath10k_sdio *ar_sdio = sdio_get_drvdata(func); + struct ath10k *ar = ar_sdio->ar; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "sdio removed func %d vendor 0x%x device 0x%x\n", + func->num, func->vendor, func->device); + + (void)ath10k_sdio_hif_disable_intrs(ar); + cancel_work_sync(&ar_sdio->wr_async_work); + ath10k_core_unregister(ar); + ath10k_core_destroy(ar); +} + +static const struct sdio_device_id ath10k_sdio_devices[] = { + {SDIO_DEVICE(QCA_MANUFACTURER_CODE, + (QCA_SDIO_ID_AR6005_BASE | 0xA))}, + {SDIO_DEVICE(QCA_MANUFACTURER_CODE, + (QCA_SDIO_ID_QCA9377_BASE | 0x1))}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, ath10k_sdio_devices); + +static struct sdio_driver ath10k_sdio_driver = { + .name = "ath10k_sdio", + .id_table = ath10k_sdio_devices, + .probe = ath10k_sdio_probe, + .remove = ath10k_sdio_remove, + .drv.pm = ATH10K_SDIO_PM_OPS, +}; + +static int __init ath10k_sdio_init(void) +{ + int ret; + + ret = sdio_register_driver(&ath10k_sdio_driver); + if (ret) + pr_err("sdio driver registration failed: %d\n", ret); + + return ret; +} + +static void __exit ath10k_sdio_exit(void) +{ + sdio_unregister_driver(&ath10k_sdio_driver); +} + +module_init(ath10k_sdio_init); +module_exit(ath10k_sdio_exit); + +MODULE_AUTHOR("Qualcomm Atheros"); +MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN SDIO devices"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h new file mode 100644 index 000000000000..3f61c67c601d --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/sdio.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. + * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDIO_H_ +#define _SDIO_H_ + +#define ATH10K_HIF_MBOX_BLOCK_SIZE 256 + +#define QCA_MANUFACTURER_ID_BASE GENMASK(11, 8) +#define QCA_MANUFACTURER_ID_AR6005_BASE 0x5 +#define QCA_MANUFACTURER_ID_QCA9377_BASE 0x7 +#define QCA_SDIO_ID_AR6005_BASE 0x500 +#define QCA_SDIO_ID_QCA9377_BASE 0x700 +#define QCA_MANUFACTURER_ID_REV_MASK 0x00FF +#define QCA_MANUFACTURER_CODE 0x271 /* Qualcomm/Atheros */ + +#define ATH10K_SDIO_MAX_BUFFER_SIZE 4096 /*Unsure of this constant*/ + +/* Mailbox address in SDIO address space */ +#define ATH10K_HIF_MBOX_BASE_ADDR 0x1000 +#define ATH10K_HIF_MBOX_WIDTH 0x800 + +#define ATH10K_HIF_MBOX_TOT_WIDTH \ + (ATH10K_HIF_MBOX_NUM_MAX * ATH10K_HIF_MBOX_WIDTH) + +#define ATH10K_HIF_MBOX0_EXT_BASE_ADDR 0x5000 +#define ATH10K_HIF_MBOX0_EXT_WIDTH (36 * 1024) +#define ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0 (56 * 1024) +#define ATH10K_HIF_MBOX1_EXT_WIDTH (36 * 1024) +#define ATH10K_HIF_MBOX_DUMMY_SPACE_SIZE (2 * 1024) + +#define ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH \ + (ATH10K_SDIO_MAX_BUFFER_SIZE - sizeof(struct ath10k_htc_hdr)) + +#define ATH10K_HIF_MBOX_NUM_MAX 4 +#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM 64 + +#define ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ (100 * HZ) + +/* HTC runs over mailbox 0 */ +#define ATH10K_HTC_MAILBOX 0 +#define ATH10K_HTC_MAILBOX_MASK BIT(ATH10K_HTC_MAILBOX) + +/* GMBOX addresses */ +#define ATH10K_HIF_GMBOX_BASE_ADDR 0x7000 +#define ATH10K_HIF_GMBOX_WIDTH 0x4000 + +/* Modified versions of the sdio.h macros. + * The macros in sdio.h can't be used easily with the FIELD_{PREP|GET} + * macros in bitfield.h, so we define our own macros here. + */ +#define ATH10K_SDIO_DRIVE_DTSX_MASK \ + (SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT) + +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_B 0 +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_A 1 +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_C 2 +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_D 3 + +/* SDIO CCCR register definitions */ +#define CCCR_SDIO_IRQ_MODE_REG 0xF0 +#define CCCR_SDIO_IRQ_MODE_REG_SDIO3 0x16 + +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR 0xF2 + +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A 0x02 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C 0x04 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D 0x08 + +#define CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS 0xF0 +#define CCCR_SDIO_ASYNC_INT_DELAY_MASK 0xC0 + +/* mode to enable special 4-bit interrupt assertion without clock */ +#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ BIT(0) +#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_SDIO3 BIT(1) + +#define ATH10K_SDIO_TARGET_DEBUG_INTR_MASK 0x01 + +/* The theoretical maximum number of RX messages that can be fetched + * from the mbox interrupt handler in one loop is derived in the following + * way: + * + * Let's assume that each packet in a bundle of the maximum bundle size + * (HTC_HOST_MAX_MSG_PER_BUNDLE) has the HTC header bundle count set + * to the maximum value (HTC_HOST_MAX_MSG_PER_BUNDLE). + * + * in this case the driver must allocate + * (HTC_HOST_MAX_MSG_PER_BUNDLE * HTC_HOST_MAX_MSG_PER_BUNDLE) skb's. + */ +#define ATH10K_SDIO_MAX_RX_MSGS \ + (HTC_HOST_MAX_MSG_PER_BUNDLE * HTC_HOST_MAX_MSG_PER_BUNDLE) + +#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u +#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF +#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000 + +struct ath10k_sdio_bus_request { + struct list_head list; + + /* sdio address */ + u32 address; + + struct sk_buff *skb; + enum ath10k_htc_ep_id eid; + int status; + /* Specifies if the current request is an HTC message. + * If not, the eid is not applicable an the TX completion handler + * associated with the endpoint will not be invoked. + */ + bool htc_msg; + /* Completion that (if set) will be invoked for non HTC requests + * (htc_msg == false) when the request has been processed. + */ + struct completion *comp; +}; + +struct ath10k_sdio_rx_data { + struct sk_buff *skb; + size_t alloc_len; + size_t act_len; + enum ath10k_htc_ep_id eid; + bool part_of_bundle; + bool last_in_bundle; + bool trailer_only; + int status; +}; + +struct ath10k_sdio_irq_proc_regs { + u8 host_int_status; + u8 cpu_int_status; + u8 error_int_status; + u8 counter_int_status; + u8 mbox_frame; + u8 rx_lookahead_valid; + u8 host_int_status2; + u8 gmbox_rx_avail; + __le32 rx_lookahead[2]; + __le32 rx_gmbox_lookahead_alias[2]; +}; + +struct ath10k_sdio_irq_enable_regs { + u8 int_status_en; + u8 cpu_int_status_en; + u8 err_int_status_en; + u8 cntr_int_status_en; +}; + +struct ath10k_sdio_irq_data { + /* protects irq_proc_reg and irq_en_reg below. + * We use a mutex here and not a spinlock since we will have the + * mutex locked while calling the sdio_memcpy_ functions. + * These function require non atomic context, and hence, spinlocks + * can be held while calling these functions. + */ + struct mutex mtx; + struct ath10k_sdio_irq_proc_regs *irq_proc_reg; + struct ath10k_sdio_irq_enable_regs *irq_en_reg; +}; + +struct ath10k_mbox_ext_info { + u32 htc_ext_addr; + u32 htc_ext_sz; +}; + +struct ath10k_mbox_info { + u32 htc_addr; + struct ath10k_mbox_ext_info ext_info[2]; + u32 block_size; + u32 block_mask; + u32 gmbox_addr; + u32 gmbox_sz; +}; + +struct ath10k_sdio { + struct sdio_func *func; + + struct ath10k_mbox_info mbox_info; + bool swap_mbox; + u32 mbox_addr[ATH10K_HTC_EP_COUNT]; + u32 mbox_size[ATH10K_HTC_EP_COUNT]; + + /* available bus requests */ + struct ath10k_sdio_bus_request bus_req[ATH10K_SDIO_BUS_REQUEST_MAX_NUM]; + /* free list of bus requests */ + struct list_head bus_req_freeq; + /* protects access to bus_req_freeq */ + spinlock_t lock; + + struct ath10k_sdio_rx_data rx_pkts[ATH10K_SDIO_MAX_RX_MSGS]; + size_t n_rx_pkts; + + struct ath10k *ar; + struct ath10k_sdio_irq_data irq_data; + + /* temporary buffer for BMI requests */ + u8 *bmi_buf; + + wait_queue_head_t irq_wq; + + bool is_disabled; + + struct workqueue_struct *workqueue; + struct work_struct wr_async_work; + struct list_head wr_asyncq; + /* protects access to wr_asyncq */ + spinlock_t wr_async_lock; +}; + +static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar) +{ + return (struct ath10k_sdio *)ar->drv_priv; +} + +#endif diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index cbac9e4252d6..8bded5da9d0d 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -205,6 +205,24 @@ struct host_interest { */ /* Bit 1 - unused */ u32 hi_fw_swap; /* 0x104 */ + + /* global arenas pointer address, used by host driver debug */ + u32 hi_dynamic_mem_arenas_addr; /* 0x108 */ + + /* allocated bytes of DRAM use by allocated */ + u32 hi_dynamic_mem_allocated; /* 0x10C */ + + /* remaining bytes of DRAM */ + u32 hi_dynamic_mem_remaining; /* 0x110 */ + + /* memory track count, configured by host */ + u32 hi_dynamic_mem_track_max; /* 0x114 */ + + /* minidump buffer */ + u32 hi_minidump; /* 0x118 */ + + /* bdata's sig and key addr */ + u32 hi_bd_sig_key; /* 0x11c */ } __packed; #define HI_ITEM(item) offsetof(struct host_interest, item) @@ -319,6 +337,12 @@ struct host_interest { #define HI_ACS_FLAGS_USE_WWAN (1 << 1) /* Use test VAP */ #define HI_ACS_FLAGS_TEST_VAP (1 << 2) +/* SDIO/mailbox ACS flag definitions */ +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET (1 << 0) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET (1 << 1) +#define HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE (1 << 2) +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK (1 << 16) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17) /* * CONSOLE FLAGS diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index d8564624415c..9d3eb258ac2f 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -137,6 +137,13 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[]) return ret; } + ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION, + ar->normal_mode_fw.fw_file.wmi_op_version); + if (ret) { + kfree_skb(skb); + return ret; + } + return cfg80211_testmode_reply(skb); } diff --git a/drivers/net/wireless/ath/ath10k/testmode_i.h b/drivers/net/wireless/ath/ath10k/testmode_i.h index ba81bf66ce85..191a8f34c8ea 100644 --- a/drivers/net/wireless/ath/ath10k/testmode_i.h +++ b/drivers/net/wireless/ath/ath10k/testmode_i.h @@ -33,6 +33,7 @@ enum ath10k_tm_attr { ATH10K_TM_ATTR_WMI_CMDID = 3, ATH10K_TM_ATTR_VERSION_MAJOR = 4, ATH10K_TM_ATTR_VERSION_MINOR = 5, + ATH10K_TM_ATTR_WMI_OP_VERSION = 6, /* keep last */ __ATH10K_TM_ATTR_AFTER_LAST, diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index 87948aff1bd5..ef717b631ff8 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -63,7 +63,7 @@ ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, return 0; } -static struct thermal_cooling_device_ops ath10k_thermal_ops = { +static const struct thermal_cooling_device_ops ath10k_thermal_ops = { .get_max_state = ath10k_thermal_get_max_throttle_state, .get_cur_state = ath10k_thermal_get_cur_throttle_state, .set_cur_state = ath10k_thermal_set_cur_throttle_state, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index f9188027a6f6..7616c1c4bbd3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2022,7 +2022,7 @@ ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar, arp->dest_ip4_addr = arg->dest_ip4_addr; ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr); - ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d interval %d\n", arg->vdev_id, arg->enabled, arg->method, arg->interval); return skb; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6afc8d27f0d5..3efb404b83c0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3304,9 +3304,8 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, if (arvif->u.ap.noa_data) if (!pskb_expand_head(bcn, 0, arvif->u.ap.noa_len, GFP_ATOMIC)) - memcpy(skb_put(bcn, arvif->u.ap.noa_len), - arvif->u.ap.noa_data, - arvif->u.ap.noa_len); + skb_put_data(bcn, arvif->u.ap.noa_data, + arvif->u.ap.noa_len); } static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, @@ -4482,31 +4481,17 @@ static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id, u32 num_units, u32 unit_len) { dma_addr_t paddr; - u32 pool_size = 0; + u32 pool_size; int idx = ar->wmi.num_mem_chunks; - void *vaddr = NULL; - - if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks)) - return -ENOMEM; + void *vaddr; - while (!vaddr && num_units) { - pool_size = num_units * round_up(unit_len, 4); - if (!pool_size) - return -EINVAL; + pool_size = num_units * round_up(unit_len, 4); + vaddr = dma_alloc_coherent(ar->dev, pool_size, &paddr, GFP_KERNEL); - vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN); - if (!vaddr) - num_units /= 2; - } - - if (!num_units) + if (!vaddr) return -ENOMEM; - paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_BIDIRECTIONAL); - if (dma_mapping_error(ar->dev, paddr)) { - kfree(vaddr); - return -ENOMEM; - } + memset(vaddr, 0, pool_size); ar->wmi.mem_chunks[idx].vaddr = vaddr; ar->wmi.mem_chunks[idx].paddr = paddr; @@ -5948,15 +5933,6 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { - if (arg->ie_len && !arg->ie) - return -EINVAL; - if (arg->n_channels && !arg->channels) - return -EINVAL; - if (arg->n_ssids && !arg->ssids) - return -EINVAL; - if (arg->n_bssids && !arg->bssids) - return -EINVAL; - if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN) return -EINVAL; if (arg->n_channels > ARRAY_SIZE(arg->channels)) @@ -6757,7 +6733,12 @@ ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void *buf, struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf; ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg); - cmd->peer_bw_rxnss_override = 0; + if (arg->peer_bw_rxnss_override) + cmd->peer_bw_rxnss_override = + __cpu_to_le32((arg->peer_bw_rxnss_override - 1) | + BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET)); + else + cmd->peer_bw_rxnss_override = 0; } static int @@ -8290,11 +8271,10 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar) /* free the host memory chunks requested by firmware */ for (i = 0; i < ar->wmi.num_mem_chunks; i++) { - dma_unmap_single(ar->dev, - ar->wmi.mem_chunks[i].paddr, - ar->wmi.mem_chunks[i].len, - DMA_BIDIRECTIONAL); - kfree(ar->wmi.mem_chunks[i].vaddr); + dma_free_coherent(ar->dev, + ar->wmi.mem_chunks[i].len, + ar->wmi.mem_chunks[i].vaddr, + ar->wmi.mem_chunks[i].paddr); } ar->wmi.num_mem_chunks = 0; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 1b4865a55595..baa38c8f847c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6028,6 +6028,8 @@ struct wmi_10_2_peer_assoc_complete_cmd { __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */ } __packed; +#define PEER_BW_RXNSS_OVERRIDE_OFFSET 31 + struct wmi_10_4_peer_assoc_complete_cmd { struct wmi_10_2_peer_assoc_complete_cmd cmd; __le32 peer_bw_rxnss_override; @@ -6051,6 +6053,7 @@ struct wmi_peer_assoc_complete_arg { u32 peer_vht_caps; enum wmi_phy_mode peer_phymode; struct wmi_vht_rate_set_arg peer_vht_rates; + u32 peer_bw_rxnss_override; }; struct wmi_peer_add_wds_entry_cmd { diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index d068df520e7a..bd7f6d7b199e 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -938,7 +938,10 @@ static int open_file_eeprom(struct inode *inode, struct file *file) } for (i = 0; i < eesize; ++i) { - AR5K_EEPROM_READ(i, val); + if (!ath5k_hw_nvram_read(ah, i, &val)) { + ret = -EIO; + goto freebuf; + } buf[i] = val; } diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index e2b7809d7886..1eea6c23976f 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -348,7 +348,7 @@ void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) if (!skb) return; - slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len); + slot = skb_put(skb, slot_len); slot->timestamp = cpu_to_le32(jiffies); slot->length = cpu_to_le32(len); memcpy(slot->payload, buf, len); diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index d127a08d60df..546243e11737 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -228,8 +228,7 @@ static int htc_issue_packets(struct htc_target *target, payload_len = packet->act_len; /* setup HTC frame header */ - htc_hdr = (struct htc_frame_hdr *) skb_push(skb, - sizeof(*htc_hdr)); + htc_hdr = skb_push(skb, sizeof(*htc_hdr)); if (!htc_hdr) { WARN_ON_ONCE(1); status = -EINVAL; @@ -383,7 +382,7 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, list_for_each_entry_safe(packet, tmp_pkt, txq, list) { ath6kl_dbg(ATH6KL_DBG_HTC, - "%s: Indicat overflowed TX pkts: %p\n", + "%s: Indicate overflowed TX pkts: %p\n", __func__, packet); action = ep->ep_cb.tx_full(ep->target, packet); if (action == HTC_SEND_FULL_DROP) { @@ -1274,8 +1273,7 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target, length = sizeof(struct htc_conn_service_msg); /* assemble connect service message */ - conn_msg = (struct htc_conn_service_msg *) skb_put(skb, - length); + conn_msg = skb_put(skb, length); if (conn_msg == NULL) { WARN_ON_ONCE(1); status = -EINVAL; @@ -1504,8 +1502,7 @@ static int ath6kl_htc_pipe_start(struct htc_target *target) skb = packet->skb; /* assemble setup complete message */ - setup = (struct htc_setup_comp_ext_msg *) skb_put(skb, - sizeof(*setup)); + setup = skb_put(skb, sizeof(*setup)); memset(setup, 0, sizeof(struct htc_setup_comp_ext_msg)); setup->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID); diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index a531e0c5c1e2..e6b2517e6334 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -399,15 +399,10 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) csum_dest = skb->csum_offset + csum_start; } - if (skb_headroom(skb) < dev->needed_headroom) { - struct sk_buff *tmp_skb = skb; - - skb = skb_realloc_headroom(skb, dev->needed_headroom); - kfree_skb(tmp_skb); - if (skb == NULL) { - dev->stats.tx_dropped++; - return 0; - } + if (skb_cow_head(skb, dev->needed_headroom)) { + dev->stats.tx_dropped++; + kfree_skb(skb); + return 0; } if (ath6kl_wmi_dix_2_dot3(ar->wmi, skb)) { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index ae3043559b6d..fe5102ca5010 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1821,8 +1821,6 @@ static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah) static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum) { REG_SET_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR); - REG_SET_BIT(ah, 0x9864, 0x7f000); - REG_SET_BIT(ah, 0x9924, 0x7f00fe); REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); REG_WRITE(ah, AR_CR, AR_CR_RXD); REG_WRITE(ah, AR_DLCL_IFS(qnum), 0); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index b84539d89f1a..f0439f2d566b 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1005,7 +1005,7 @@ static void ath_scan_send_probe(struct ath_softc *sc, info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; if (req->ie_len) - memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); + skb_put_data(skb, req->ie, req->ie_len); skb_set_queue_mapping(skb, IEEE80211_AC_VO); @@ -1521,13 +1521,11 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, noa_desc = !!avp->offchannel_duration + !!avp->noa_duration; noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; - hdr = skb_put(skb, sizeof(noa_ie_hdr)); - memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr)); + hdr = skb_put_data(skb, noa_ie_hdr, sizeof(noa_ie_hdr)); hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; hdr[7] = noa_len; - noa = (void *) skb_put(skb, noa_len); - memset(noa, 0, noa_len); + noa = skb_put_zero(skb, noa_len); noa->index = avp->noa_index; noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp); diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index c67d0e08bd4c..099f3d45c594 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -369,7 +369,7 @@ void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, { struct ath_regulatory *reg = ath9k_hw_regulatory(ah); - if (reg->power_limit != new_txpow) + if (ah->curchan && reg->power_limit != new_txpow) ath9k_hw_set_txpowerlimit(ah, new_txpow, false); /* read back in case value is clamped */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 6ccf24814514..6fbd5559c0c0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -143,7 +143,7 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) if (ah->eeprom_blob) ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); - else if (pdata && !pdata->use_eeprom && pdata->eeprom_data) + else if (pdata && !pdata->use_eeprom) ret = ath9k_hw_nvram_read_pdata(pdata, off, data); else ret = common->bus_ops->eeprom_read(common, off, data); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 12aa8abbcba4..0d9687a2aa98 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -199,7 +199,7 @@ static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev, cmd->skb = skb; cmd->hif_dev = hif_dev; - hdr = (__le16 *) skb_push(skb, 4); + hdr = skb_push(skb, 4); *hdr++ = cpu_to_le16(skb->len - 4); *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 8e6dae23669b..1bf63a4efb4c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -26,8 +26,7 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, struct htc_endpoint *endpoint = &target->endpoint[epid]; int status; - hdr = (struct htc_frame_hdr *) - skb_push(skb, sizeof(struct htc_frame_hdr)); + hdr = skb_push(skb, sizeof(struct htc_frame_hdr)); hdr->endpoint_id = epid; hdr->flags = flags; hdr->payload_len = cpu_to_be16(len); @@ -156,8 +155,7 @@ static int htc_config_pipe_credits(struct htc_target *target) } skb_reserve(skb, sizeof(struct htc_frame_hdr)); - cp_msg = (struct htc_config_pipe_msg *) - skb_put(skb, sizeof(struct htc_config_pipe_msg)); + cp_msg = skb_put(skb, sizeof(struct htc_config_pipe_msg)); cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID); cp_msg->pipe_id = USB_WLAN_TX_PIPE; @@ -195,8 +193,7 @@ static int htc_setup_complete(struct htc_target *target) } skb_reserve(skb, sizeof(struct htc_frame_hdr)); - comp_msg = (struct htc_comp_msg *) - skb_put(skb, sizeof(struct htc_comp_msg)); + comp_msg = skb_put(skb, sizeof(struct htc_comp_msg)); comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID); target->htc_flags |= HTC_OP_START_WAIT; @@ -265,8 +262,7 @@ int htc_connect_service(struct htc_target *target, skb_reserve(skb, sizeof(struct htc_frame_hdr)); - conn_msg = (struct htc_conn_svc_msg *) - skb_put(skb, sizeof(struct htc_conn_svc_msg)); + conn_msg = skb_put(skb, sizeof(struct htc_conn_svc_msg)); conn_msg->service_id = cpu_to_be16(service_connreq->service_id); conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID); conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9e65d14e7b1e..8b4ac7f0a09b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -731,12 +731,12 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_rng_start(sc); + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); - ath9k_rng_start(sc); - return 0; } @@ -826,10 +826,10 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); - ath9k_rng_stop(sc); - mutex_lock(&sc->mutex); + ath9k_rng_stop(sc); + ath_cancel_work(sc); if (test_bit(ATH_OP_INVALID, &common->op_flags)) { diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 66596b95273f..cf23fd815211 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -548,7 +548,7 @@ void ath_mci_intr(struct ath_softc *sc) if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; - offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET); + ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c index 568b1c6c2b2b..f9d3d6eedd3c 100644 --- a/drivers/net/wireless/ath/ath9k/rng.c +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -24,6 +24,8 @@ #define ATH9K_RNG_BUF_SIZE 320 #define ATH9K_RNG_ENTROPY(x) (((x) * 8 * 10) >> 5) /* quality: 10/32 */ +static DECLARE_WAIT_QUEUE_HEAD(rng_queue); + static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size) { int i, j; @@ -85,7 +87,9 @@ static int ath9k_rng_kthread(void *data) ATH9K_RNG_BUF_SIZE); if (unlikely(!bytes_read)) { delay = ath9k_rng_delay_get(++fail_stats); - msleep_interruptible(delay); + wait_event_interruptible_timeout(rng_queue, + kthread_should_stop(), + msecs_to_jiffies(delay)); continue; } @@ -120,6 +124,8 @@ void ath9k_rng_start(struct ath_softc *sc) void ath9k_rng_stop(struct ath_softc *sc) { - if (sc->rng_task) + if (sc->rng_task) { kthread_stop(sc->rng_task); + sc->rng_task = NULL; + } } diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 16aca9e28b77..49ed1afb913c 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -153,7 +153,7 @@ static int ath9k_tx99_init(struct ath_softc *sc) sc->tx99_power, sc->tx99_power / 2); - /* We leave the harware awake as it will be chugging on */ + /* We leave the hardware awake as it will be chugging on */ return 0; } @@ -189,22 +189,27 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, if (strtobool(buf, &start)) return -EINVAL; + mutex_lock(&sc->mutex); + if (start == sc->tx99_state) { if (!start) - return count; + goto out; ath_dbg(common, XMIT, "Resetting TX99\n"); ath9k_tx99_deinit(sc); } if (!start) { ath9k_tx99_deinit(sc); - return count; + goto out; } r = ath9k_tx99_init(sc); - if (r) + if (r) { + mutex_unlock(&sc->mutex); return r; - + } +out: + mutex_unlock(&sc->mutex); return count; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 9c16e2a6d185..64a354fa78ab 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -277,7 +277,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, struct wmi_cmd_hdr *hdr; unsigned long flags; - hdr = (struct wmi_cmd_hdr *) skb_push(skb, sizeof(struct wmi_cmd_hdr)); + hdr = skb_push(skb, sizeof(struct wmi_cmd_hdr)); hdr->command_id = cpu_to_be16(cmd); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); @@ -298,7 +298,6 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, u16 headroom = sizeof(struct htc_frame_hdr) + sizeof(struct wmi_cmd_hdr); struct sk_buff *skb; - u8 *data; unsigned long time_left; int ret = 0; @@ -312,8 +311,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, skb_reserve(skb, headroom); if (cmd_len != 0 && cmd_buf != NULL) { - data = (u8 *) skb_put(skb, cmd_len); - memcpy(data, cmd_buf, cmd_len); + skb_put_data(skb, cmd_buf, cmd_len); } mutex_lock(&wmi->op_mutex); diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index b2166726b05d..705063259c8f 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -481,7 +481,7 @@ static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len) skb = dev_alloc_skb(len + reserved); if (likely(skb)) { skb_reserve(skb, reserved); - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); } return skb; @@ -916,7 +916,7 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) } } - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + skb_put_data(ar->rx_failover, tbuf, tlen); ar->rx_failover_missing -= tlen; if (ar->rx_failover_missing <= 0) { @@ -958,7 +958,7 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) * the rx - descriptor comes round again. */ - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + skb_put_data(ar->rx_failover, tbuf, tlen); ar->rx_failover_missing = clen - tlen; return; } diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 2bf04c9edc98..0cb5b58925dc 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -991,7 +991,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar, else cvif = NULL; - txc = (void *)skb_push(skb, sizeof(*txc)); + txc = skb_push(skb, sizeof(*txc)); memset(txc, 0, sizeof(*txc)); SET_VAL(CARL9170_TX_SUPER_MISC_QUEUE, txc->s.misc, hw_queue); diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 89bf2f9eca1d..4ae21da78e9e 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -10,7 +10,6 @@ wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o wil6210-y += rx_reorder.o -wil6210-y += ioctl.o wil6210-y += fw.o wil6210-y += pm.o wil6210-y += pmc.o diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index fdaa99c541ac..0b5383a62d42 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -16,6 +16,7 @@ #include <linux/etherdevice.h> #include <linux/moduleparam.h> +#include <net/netlink.h> #include "wil6210.h" #include "wmi.h" @@ -41,6 +42,126 @@ static struct ieee80211_channel wil_60ghz_channels[] = { /* channel 4 not supported yet */ }; +/* Vendor id to be used in vendor specific command and events + * to user space. + * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, + * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and + * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in + * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that + */ + +#define QCA_NL80211_VENDOR_ID 0x001374 + +#define WIL_MAX_RF_SECTORS (128) +#define WIL_CID_ALL (0xff) + +enum qca_wlan_vendor_attr_rf_sector { + QCA_ATTR_MAC_ADDR = 6, + QCA_ATTR_PAD = 13, + QCA_ATTR_TSF = 29, + QCA_ATTR_DMG_RF_SECTOR_INDEX = 30, + QCA_ATTR_DMG_RF_SECTOR_TYPE = 31, + QCA_ATTR_DMG_RF_MODULE_MASK = 32, + QCA_ATTR_DMG_RF_SECTOR_CFG = 33, + QCA_ATTR_DMG_RF_SECTOR_MAX, +}; + +enum qca_wlan_vendor_attr_dmg_rf_sector_type { + QCA_ATTR_DMG_RF_SECTOR_TYPE_RX, + QCA_ATTR_DMG_RF_SECTOR_TYPE_TX, + QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX +}; + +enum qca_wlan_vendor_attr_dmg_rf_sector_cfg { + QCA_ATTR_DMG_RF_SECTOR_CFG_INVALID = 0, + QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX, + QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0, + QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1, + QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2, + QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI, + QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO, + QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16, + + /* keep last */ + QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST, + QCA_ATTR_DMG_RF_SECTOR_CFG_MAX = + QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1 +}; + +static const struct +nla_policy wil_rf_sector_policy[QCA_ATTR_DMG_RF_SECTOR_MAX + 1] = { + [QCA_ATTR_MAC_ADDR] = { .len = ETH_ALEN }, + [QCA_ATTR_DMG_RF_SECTOR_INDEX] = { .type = NLA_U16 }, + [QCA_ATTR_DMG_RF_SECTOR_TYPE] = { .type = NLA_U8 }, + [QCA_ATTR_DMG_RF_MODULE_MASK] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG] = { .type = NLA_NESTED }, +}; + +static const struct +nla_policy wil_rf_sector_cfg_policy[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1] = { + [QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] = { .type = NLA_U8 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16] = { .type = NLA_U32 }, +}; + +enum qca_nl80211_vendor_subcmds { + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG = 139, + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140, + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141, + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142, +}; + +static int wil_rf_sector_get_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +static int wil_rf_sector_set_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +static int wil_rf_sector_get_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +static int wil_rf_sector_set_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +/* vendor specific commands */ +static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = { + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_get_cfg + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_set_cfg + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_get_selected + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_set_selected + }, +}; + static struct ieee80211_supported_band wil_band_60ghz = { .channels = wil_60ghz_channels, .n_channels = ARRAY_SIZE(wil_60ghz_channels), @@ -1325,6 +1446,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); wil_set_recovery_state(wil, fw_recovery_idle); + set_bit(wil_status_resetting, wil->status); + mutex_lock(&wil->mutex); wmi_pcp_stop(wil); @@ -1571,6 +1694,42 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, return wil_ps_update(wil, ps_profile); } +static int wil_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + /* Setting the wakeup trigger based on wow is TBD */ + + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + + rc = wil_can_suspend(wil, false); + if (rc) + goto out; + + wil_dbg_pm(wil, "suspending\n"); + + wil_p2p_stop_discovery(wil); + + wil_abort_scan(wil, true); + +out: + return rc; +} + +static int wil_cfg80211_resume(struct wiphy *wiphy) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + wil_dbg_pm(wil, "resuming\n"); + + return 0; +} + static const struct cfg80211_ops wil_cfg80211_ops = { .add_virtual_intf = wil_cfg80211_add_iface, .del_virtual_intf = wil_cfg80211_del_iface, @@ -1602,6 +1761,8 @@ static const struct cfg80211_ops wil_cfg80211_ops = { .start_p2p_device = wil_cfg80211_start_p2p_device, .stop_p2p_device = wil_cfg80211_stop_p2p_device, .set_power_mgmt = wil_cfg80211_set_power_mgmt, + .suspend = wil_cfg80211_suspend, + .resume = wil_cfg80211_resume, }; static void wil_wiphy_init(struct wiphy *wiphy) @@ -1637,6 +1798,9 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->mgmt_stypes = wil_mgmt_stypes; wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; + + wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands); + wiphy->vendor_commands = wil_nl80211_vendor_commands; } struct wireless_dev *wil_cfg80211_init(struct device *dev) @@ -1695,3 +1859,452 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil) kfree(p2p_wdev); } } + +static int wil_rf_sector_status_to_rc(u8 status) +{ + switch (status) { + case WMI_RF_SECTOR_STATUS_SUCCESS: + return 0; + case WMI_RF_SECTOR_STATUS_BAD_PARAMETERS_ERROR: + return -EINVAL; + case WMI_RF_SECTOR_STATUS_BUSY_ERROR: + return -EAGAIN; + case WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR: + return -EOPNOTSUPP; + default: + return -EINVAL; + } +} + +static int wil_rf_sector_get_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + u16 sector_index; + u8 sector_type; + u32 rf_modules_vec; + struct wmi_get_rf_sector_params_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_get_rf_sector_params_done_event evt; + } __packed reply; + struct sk_buff *msg; + struct nlattr *nl_cfgs, *nl_cfg; + u32 i; + struct wmi_rf_sector_info *si; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] || + !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] || + !tb[QCA_ATTR_DMG_RF_MODULE_MASK]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + + sector_index = nla_get_u16( + tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]); + if (sector_index >= WIL_MAX_RF_SECTORS) { + wil_err(wil, "Invalid sector index %d\n", sector_index); + return -EINVAL; + } + + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + rf_modules_vec = nla_get_u32( + tb[QCA_ATTR_DMG_RF_MODULE_MASK]); + if (rf_modules_vec >= BIT(WMI_MAX_RF_MODULES_NUM)) { + wil_err(wil, "Invalid rf module mask 0x%x\n", rf_modules_vec); + return -EINVAL; + } + + cmd.sector_idx = cpu_to_le16(sector_index); + cmd.sector_type = sector_type; + cmd.rf_modules_vec = rf_modules_vec & 0xFF; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd), + WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + if (reply.evt.status) { + wil_err(wil, "get rf sector cfg failed with status %d\n", + reply.evt.status); + return wil_rf_sector_status_to_rc(reply.evt.status); + } + + msg = cfg80211_vendor_cmd_alloc_reply_skb( + wiphy, 64 * WMI_MAX_RF_MODULES_NUM); + if (!msg) + return -ENOMEM; + + if (nla_put_u64_64bit(msg, QCA_ATTR_TSF, + le64_to_cpu(reply.evt.tsf), + QCA_ATTR_PAD)) + goto nla_put_failure; + + nl_cfgs = nla_nest_start(msg, QCA_ATTR_DMG_RF_SECTOR_CFG); + if (!nl_cfgs) + goto nla_put_failure; + for (i = 0; i < WMI_MAX_RF_MODULES_NUM; i++) { + if (!(rf_modules_vec & BIT(i))) + continue; + nl_cfg = nla_nest_start(msg, i); + if (!nl_cfg) + goto nla_put_failure; + si = &reply.evt.sectors_info[i]; + if (nla_put_u8(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX, + i) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0, + le32_to_cpu(si->etype0)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1, + le32_to_cpu(si->etype1)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2, + le32_to_cpu(si->etype2)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI, + le32_to_cpu(si->psh_hi)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO, + le32_to_cpu(si->psh_lo)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16, + le32_to_cpu(si->dtype_swch_off))) + goto nla_put_failure; + nla_nest_end(msg, nl_cfg); + } + + nla_nest_end(msg, nl_cfgs); + rc = cfg80211_vendor_cmd_reply(msg); + return rc; +nla_put_failure: + kfree_skb(msg); + return -ENOBUFS; +} + +static int wil_rf_sector_set_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc, tmp; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1]; + u16 sector_index, rf_module_index; + u8 sector_type; + u32 rf_modules_vec = 0; + struct wmi_set_rf_sector_params_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_set_rf_sector_params_done_event evt; + } __packed reply; + struct nlattr *nl_cfg; + struct wmi_rf_sector_info *si; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] || + !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] || + !tb[QCA_ATTR_DMG_RF_SECTOR_CFG]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + + sector_index = nla_get_u16( + tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]); + if (sector_index >= WIL_MAX_RF_SECTORS) { + wil_err(wil, "Invalid sector index %d\n", sector_index); + return -EINVAL; + } + + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + memset(&cmd, 0, sizeof(cmd)); + + cmd.sector_idx = cpu_to_le16(sector_index); + cmd.sector_type = sector_type; + nla_for_each_nested(nl_cfg, tb[QCA_ATTR_DMG_RF_SECTOR_CFG], + tmp) { + rc = nla_parse_nested(tb2, QCA_ATTR_DMG_RF_SECTOR_CFG_MAX, + nl_cfg, wil_rf_sector_cfg_policy, + NULL); + if (rc) { + wil_err(wil, "invalid sector cfg\n"); + return -EINVAL; + } + + if (!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16]) { + wil_err(wil, "missing cfg params\n"); + return -EINVAL; + } + + rf_module_index = nla_get_u8( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX]); + if (rf_module_index >= WMI_MAX_RF_MODULES_NUM) { + wil_err(wil, "invalid RF module index %d\n", + rf_module_index); + return -EINVAL; + } + rf_modules_vec |= BIT(rf_module_index); + si = &cmd.sectors_info[rf_module_index]; + si->etype0 = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0])); + si->etype1 = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1])); + si->etype2 = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2])); + si->psh_hi = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI])); + si->psh_lo = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO])); + si->dtype_swch_off = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16])); + } + + cmd.rf_modules_vec = rf_modules_vec & 0xFF; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd), + WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + return wil_rf_sector_status_to_rc(reply.evt.status); +} + +static int wil_rf_sector_get_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + u8 sector_type, mac_addr[ETH_ALEN]; + int cid = 0; + struct wmi_get_selected_rf_sector_index_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_get_selected_rf_sector_index_done_event evt; + } __packed reply; + struct sk_buff *msg; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + if (tb[QCA_ATTR_MAC_ADDR]) { + ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR])); + cid = wil_find_cid(wil, mac_addr); + if (cid < 0) { + wil_err(wil, "invalid MAC address %pM\n", mac_addr); + return -ENOENT; + } + } else { + if (test_bit(wil_status_fwconnected, wil->status)) { + wil_err(wil, "must specify MAC address when connected\n"); + return -EINVAL; + } + } + + memset(&cmd, 0, sizeof(cmd)); + cmd.cid = (u8)cid; + cmd.sector_type = sector_type; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID, + &cmd, sizeof(cmd), + WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + if (reply.evt.status) { + wil_err(wil, "get rf selected sector cfg failed with status %d\n", + reply.evt.status); + return wil_rf_sector_status_to_rc(reply.evt.status); + } + + msg = cfg80211_vendor_cmd_alloc_reply_skb( + wiphy, 64 * WMI_MAX_RF_MODULES_NUM); + if (!msg) + return -ENOMEM; + + if (nla_put_u64_64bit(msg, QCA_ATTR_TSF, + le64_to_cpu(reply.evt.tsf), + QCA_ATTR_PAD) || + nla_put_u16(msg, QCA_ATTR_DMG_RF_SECTOR_INDEX, + le16_to_cpu(reply.evt.sector_idx))) + goto nla_put_failure; + + rc = cfg80211_vendor_cmd_reply(msg); + return rc; +nla_put_failure: + kfree_skb(msg); + return -ENOBUFS; +} + +static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil, + u16 sector_index, + u8 sector_type, u8 cid) +{ + struct wmi_set_selected_rf_sector_index_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_set_selected_rf_sector_index_done_event evt; + } __packed reply; + int rc; + + memset(&cmd, 0, sizeof(cmd)); + cmd.sector_idx = cpu_to_le16(sector_index); + cmd.sector_type = sector_type; + cmd.cid = (u8)cid; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID, + &cmd, sizeof(cmd), + WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + return wil_rf_sector_status_to_rc(reply.evt.status); +} + +static int wil_rf_sector_set_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + u16 sector_index; + u8 sector_type, mac_addr[ETH_ALEN], i; + int cid = 0; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] || + !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + + sector_index = nla_get_u16( + tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]); + if (sector_index >= WIL_MAX_RF_SECTORS && + sector_index != WMI_INVALID_RF_SECTOR_INDEX) { + wil_err(wil, "Invalid sector index %d\n", sector_index); + return -EINVAL; + } + + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + if (tb[QCA_ATTR_MAC_ADDR]) { + ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR])); + if (!is_broadcast_ether_addr(mac_addr)) { + cid = wil_find_cid(wil, mac_addr); + if (cid < 0) { + wil_err(wil, "invalid MAC address %pM\n", + mac_addr); + return -ENOENT; + } + } else { + if (sector_index != WMI_INVALID_RF_SECTOR_INDEX) { + wil_err(wil, "broadcast MAC valid only with unlocking\n"); + return -EINVAL; + } + cid = -1; + } + } else { + if (test_bit(wil_status_fwconnected, wil->status)) { + wil_err(wil, "must specify MAC address when connected\n"); + return -EINVAL; + } + /* otherwise, using cid=0 for unassociated station */ + } + + if (cid >= 0) { + rc = wil_rf_sector_wmi_set_selected(wil, sector_index, + sector_type, cid); + } else { + /* unlock all cids */ + rc = wil_rf_sector_wmi_set_selected( + wil, WMI_INVALID_RF_SECTOR_INDEX, sector_type, + WIL_CID_ALL); + if (rc == -EINVAL) { + for (i = 0; i < WIL6210_MAX_CID; i++) { + rc = wil_rf_sector_wmi_set_selected( + wil, WMI_INVALID_RF_SECTOR_INDEX, + sector_type, i); + /* the FW will silently ignore and return + * success for unused cid, so abort the loop + * on any other error + */ + if (rc) { + wil_err(wil, "unlock cid %d failed with status %d\n", + i, rc); + break; + } + } + } + } + + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 5648ebbd0e16..f82506d276d3 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -509,6 +509,10 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, void *buf; size_t ret; + if (test_bit(wil_status_suspending, wil_blob->wil->status) || + test_bit(wil_status_suspended, wil_blob->wil->status)) + return 0; + if (pos < 0) return -EINVAL; @@ -795,15 +799,11 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, struct wireless_dev *wdev = wil_to_wdev(wil); struct cfg80211_mgmt_tx_params params; int rc; - void *frame = kmalloc(len, GFP_KERNEL); + void *frame; - if (!frame) - return -ENOMEM; - - if (copy_from_user(frame, buf, len)) { - kfree(frame); - return -EIO; - } + frame = memdup_user(buf, len); + if (IS_ERR(frame)) + return PTR_ERR(frame); params.buf = frame; params.len = len; @@ -1604,6 +1604,49 @@ static const struct file_operations fops_fw_version = { .llseek = seq_lseek, }; +/*---------suspend_stats---------*/ +static ssize_t wil_write_suspend_stats(struct file *file, + const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + + memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); + + return len; +} + +static ssize_t wil_read_suspend_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + static char text[400]; + int n; + + n = snprintf(text, sizeof(text), + "Suspend statistics:\n" + "successful suspends:%ld failed suspends:%ld\n" + "successful resumes:%ld failed resumes:%ld\n" + "rejected by host:%ld rejected by device:%ld\n", + wil->suspend_stats.successful_suspends, + wil->suspend_stats.failed_suspends, + wil->suspend_stats.successful_resumes, + wil->suspend_stats.failed_resumes, + wil->suspend_stats.rejected_by_host, + wil->suspend_stats.rejected_by_device); + + n = min_t(int, n, sizeof(text)); + + return simple_read_from_buffer(user_buf, count, ppos, text, n); +} + +static const struct file_operations fops_suspend_stats = { + .read = wil_read_suspend_stats, + .write = wil_write_suspend_stats, + .open = simple_open, +}; + /*----------------*/ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, struct dentry *dbg) @@ -1656,6 +1699,7 @@ static const struct { {"led_blink_time", 0644, &fops_led_blink_time}, {"fw_capabilities", 0444, &fops_fw_capabilities}, {"fw_version", 0444, &fops_fw_version}, + {"suspend_stats", 0644, &fops_suspend_stats}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, @@ -1702,6 +1746,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(discovery_mode, 0644, doff_u8), WIL_FIELD(chip_revision, 0444, doff_u8), WIL_FIELD(abft_len, 0644, doff_u8), + WIL_FIELD(wakeup_trigger, 0644, doff_u8), {}, }; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index cab1e5c0e374..cad8a95c4e4e 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -467,6 +467,12 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) wil6210_unmask_irq_pseudo(wil); + if (wil->suspend_resp_rcvd) { + wil_dbg_irq(wil, "set suspend_resp_comp to true\n"); + wil->suspend_resp_comp = true; + wake_up_interruptible(&wil->wq); + } + return IRQ_HANDLED; } diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c deleted file mode 100644 index 630380078236..000000000000 --- a/drivers/net/wireless/ath/wil6210/ioctl.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2014 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/uaccess.h> - -#include "wil6210.h" -#include <uapi/linux/wil6210_uapi.h> - -#define wil_hex_dump_ioctl(prefix_str, buf, len) \ - print_hex_dump_debug("DBG[IOC ]" prefix_str, \ - DUMP_PREFIX_OFFSET, 16, 1, buf, len, true) -#define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg) - -static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr, - uint32_t size, enum wil_memio_op op) -{ - void __iomem *a; - u32 off; - - switch (op & wil_mmio_addr_mask) { - case wil_mmio_addr_linker: - a = wmi_buffer(wil, cpu_to_le32(addr)); - break; - case wil_mmio_addr_ahb: - a = wmi_addr(wil, addr); - break; - case wil_mmio_addr_bar: - a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF); - break; - default: - wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op); - return NULL; - } - - off = a - wil->csr; - if (size >= WIL6210_MEM_SIZE - off) { - wil_err(wil, "Requested block does not fit into memory: " - "off = 0x%08x size = 0x%08x\n", off, size); - return NULL; - } - - return a; -} - -static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data) -{ - struct wil_memio io; - void __iomem *a; - bool need_copy = false; - - if (copy_from_user(&io, data, sizeof(io))) - return -EFAULT; - - wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n", - io.addr, io.val, io.op); - - a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op); - if (!a) { - wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, - io.op); - return -EINVAL; - } - /* operation */ - switch (io.op & wil_mmio_op_mask) { - case wil_mmio_read: - io.val = readl(a); - need_copy = true; - break; - case wil_mmio_write: - writel(io.val, a); - wmb(); /* make sure write propagated to HW */ - break; - default: - wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); - return -EINVAL; - } - - if (need_copy) { - wil_dbg_ioctl(wil, "IO done: addr = 0x%08x" - " val = 0x%08x op = 0x%08x\n", - io.addr, io.val, io.op); - if (copy_to_user(data, &io, sizeof(io))) - return -EFAULT; - } - - return 0; -} - -static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data) -{ - struct wil_memio_block io; - void *block; - void __iomem *a; - int rc = 0; - - if (copy_from_user(&io, data, sizeof(io))) - return -EFAULT; - - wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n", - io.addr, io.size, io.op); - - /* size */ - if (io.size % 4) { - wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size); - return -EINVAL; - } - - a = wil_ioc_addr(wil, io.addr, io.size, io.op); - if (!a) { - wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, - io.op); - return -EINVAL; - } - - block = kmalloc(io.size, GFP_USER); - if (!block) - return -ENOMEM; - - /* operation */ - switch (io.op & wil_mmio_op_mask) { - case wil_mmio_read: - wil_memcpy_fromio_32(block, a, io.size); - wil_hex_dump_ioctl("Read ", block, io.size); - if (copy_to_user(io.block, block, io.size)) { - rc = -EFAULT; - goto out_free; - } - break; - case wil_mmio_write: - if (copy_from_user(block, io.block, io.size)) { - rc = -EFAULT; - goto out_free; - } - wil_memcpy_toio_32(a, block, io.size); - wmb(); /* make sure write propagated to HW */ - wil_hex_dump_ioctl("Write ", block, io.size); - break; - default: - wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); - rc = -EINVAL; - break; - } - -out_free: - kfree(block); - return rc; -} - -int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd) -{ - int ret; - - switch (cmd) { - case WIL_IOCTL_MEMIO: - ret = wil_ioc_memio_dword(wil, data); - break; - case WIL_IOCTL_MEMIO_BLOCK: - ret = wil_ioc_memio_block(wil, data); - break; - default: - wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd); - return -ENOIOCTLCMD; - } - - wil_dbg_ioctl(wil, "ioctl(0x%04x) -> %d\n", cmd, ret); - return ret; -} diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 32086792dfc3..daf944a71901 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -576,6 +576,9 @@ int wil_priv_init(struct wil6210_priv *wil) wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; + wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST | + WMI_WAKEUP_TRIGGER_BCAST; + return 0; out_wmi_wq: @@ -586,8 +589,10 @@ out_wmi_wq: void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) { - if (wil->platform_ops.bus_request) + if (wil->platform_ops.bus_request) { + wil->bus_request_kbps = kbps; wil->platform_ops.bus_request(wil->platform_handle, kbps); + } } /** diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 708facd5f667..4a6ab2d0fdf1 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -42,20 +42,12 @@ static int wil_stop(struct net_device *ndev) return wil_down(wil); } -static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) -{ - struct wil6210_priv *wil = ndev_to_wil(ndev); - - return wil_ioctl(wil, ifr->ifr_data, cmd); -} - static const struct net_device_ops wil_netdev_ops = { .ndo_open = wil_open, .ndo_stop = wil_stop, .ndo_start_xmit = wil_start_xmit, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = wil_do_ioctl, }; static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index b38515fc7ce7..d571feb2370e 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,6 +26,10 @@ static bool use_msi = true; module_param(use_msi, bool, 0444); MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); +static bool ftm_mode; +module_param(ftm_mode, bool, 0444); +MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false"); + #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP static int wil6210_pm_notify(struct notifier_block *notify_block, @@ -36,13 +40,15 @@ static int wil6210_pm_notify(struct notifier_block *notify_block, static void wil_set_capabilities(struct wil6210_priv *wil) { + const char *wil_fw_name; u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & RGF_USER_REVISION_ID_MASK); bitmap_zero(wil->hw_capabilities, hw_capability_last); bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); - wil->wil_fw_name = WIL_FW_NAME_DEFAULT; + wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT : + WIL_FW_NAME_DEFAULT; wil->chip_revision = chip_revision; switch (jtag_id) { @@ -51,9 +57,11 @@ void wil_set_capabilities(struct wil6210_priv *wil) case REVISION_ID_SPARROW_D0: wil->hw_name = "Sparrow D0"; wil->hw_version = HW_VER_SPARROW_D0; - if (wil_fw_verify_file_exists(wil, - WIL_FW_NAME_SPARROW_PLUS)) - wil->wil_fw_name = WIL_FW_NAME_SPARROW_PLUS; + wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_SPARROW_PLUS : + WIL_FW_NAME_SPARROW_PLUS; + + if (wil_fw_verify_file_exists(wil, wil_fw_name)) + wil->wil_fw_name = wil_fw_name; break; case REVISION_ID_SPARROW_B0: wil->hw_name = "Sparrow B0"; @@ -104,8 +112,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only); - pdev->msi_enabled = 0; - pci_set_master(pdev); wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); @@ -183,6 +189,13 @@ static int wil_platform_rop_fw_recovery(void *wil_handle) return 0; } +static void wil_platform_ops_uninit(struct wil6210_priv *wil) +{ + if (wil->platform_ops.uninit) + wil->platform_ops.uninit(wil->platform_handle); + memset(&wil->platform_ops, 0, sizeof(wil->platform_ops)); +} + static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct wil6210_priv *wil; @@ -192,16 +205,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) .ramdump = wil_platform_rop_ramdump, .fw_recovery = wil_platform_rop_fw_recovery, }; + u32 bar_size = pci_resource_len(pdev, 0); /* check HW */ dev_info(&pdev->dev, WIL_NAME - " device found [%04x:%04x] (rev %x)\n", - (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); - - if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { - dev_err(&pdev->dev, "Not " WIL_NAME "? " - "BAR0 size is %lu while expecting %lu\n", - (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); + " device found [%04x:%04x] (rev %x) bar size 0x%x\n", + (int)pdev->vendor, (int)pdev->device, (int)pdev->revision, + bar_size); + + if ((bar_size < WIL6210_MIN_MEM_SIZE) || + (bar_size > WIL6210_MAX_MEM_SIZE)) { + dev_err(&pdev->dev, "Unexpected BAR0 size 0x%x\n", + bar_size); return -ENODEV; } @@ -214,6 +229,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil->pdev = pdev; pci_set_drvdata(pdev, wil); + wil->bar_size = bar_size; /* rollback to if_free */ wil->platform_handle = @@ -241,7 +257,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) } rc = pci_enable_device(pdev); - if (rc) { + if (rc && pdev->msi_enabled == 0) { wil_err(wil, "pci_enable_device failed, retry with MSI only\n"); /* Work around for platforms that can't allocate IRQ: @@ -256,6 +272,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_plat; } /* rollback to err_disable_pdev */ + pci_set_power_state(pdev, PCI_D0); rc = pci_request_region(pdev, 0, WIL_NAME); if (rc) { @@ -276,6 +293,15 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil_set_capabilities(wil); wil6210_clear_irq(wil); + wil->keep_radio_on_during_sleep = + wil->platform_ops.keep_radio_on_during_sleep && + wil->platform_ops.keep_radio_on_during_sleep( + wil->platform_handle) && + test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities); + + wil_info(wil, "keep_radio_on_during_sleep (%d)\n", + wil->keep_radio_on_during_sleep); + /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { @@ -316,8 +342,7 @@ err_release_reg: err_disable_pdev: pci_disable_device(pdev); err_plat: - if (wil->platform_ops.uninit) - wil->platform_ops.uninit(wil->platform_handle); + wil_platform_ops_uninit(wil); if_free: wil_if_free(wil); @@ -346,8 +371,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) pci_iounmap(pdev, csr); pci_release_region(pdev, 0); pci_disable_device(pdev); - if (wil->platform_ops.uninit) - wil->platform_ops.uninit(wil->platform_handle); + wil_platform_ops_uninit(wil); wil_if_free(wil); } @@ -374,15 +398,16 @@ static int wil6210_suspend(struct device *dev, bool is_runtime) goto out; rc = wil_suspend(wil, is_runtime); - if (rc) - goto out; - - /* TODO: how do I bring card in low power state? */ - - /* disable bus mastering */ - pci_clear_master(pdev); - /* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */ + if (!rc) { + wil->suspend_stats.successful_suspends++; + /* If platform device supports keep_radio_on_during_sleep + * it will control PCIe master + */ + if (!wil->keep_radio_on_during_sleep) + /* disable bus mastering */ + pci_clear_master(pdev); + } out: return rc; } @@ -395,12 +420,21 @@ static int wil6210_resume(struct device *dev, bool is_runtime) wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); - /* allow master */ - pci_set_master(pdev); - + /* If platform device supports keep_radio_on_during_sleep it will + * control PCIe master + */ + if (!wil->keep_radio_on_during_sleep) + /* allow master */ + pci_set_master(pdev); rc = wil_resume(wil, is_runtime); - if (rc) - pci_clear_master(pdev); + if (rc) { + wil_err(wil, "device failed to resume (%d)\n", rc); + wil->suspend_stats.failed_resumes++; + if (!wil->keep_radio_on_during_sleep) + pci_clear_master(pdev); + } else { + wil->suspend_stats.successful_resumes++; + } return rc; } diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 2ae4fe85cc8c..ce1f384e7f8e 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -15,6 +15,7 @@ */ #include "wil6210.h" +#include <linux/jiffies.h> int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) { @@ -61,20 +62,170 @@ out: wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n", is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); + if (rc) + wil->suspend_stats.rejected_by_host++; + return rc; } -int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +static int wil_resume_keep_radio_on(struct wil6210_priv *wil) { int rc = 0; - struct net_device *ndev = wil_to_ndev(wil); - wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + /* wil_status_resuming will be cleared when getting + * WMI_TRAFFIC_RESUME_EVENTID + */ + set_bit(wil_status_resuming, wil->status); + clear_bit(wil_status_suspended, wil->status); + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_unmask_irq(wil); - if (test_bit(wil_status_suspended, wil->status)) { - wil_dbg_pm(wil, "trying to suspend while suspended\n"); - return 0; + wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend); + + /* Send WMI resume request to the device */ + rc = wmi_resume(wil); + if (rc) { + wil_err(wil, "device failed to resume (%d), resetting\n", rc); + rc = wil_down(wil); + if (rc) { + wil_err(wil, "wil_down failed (%d)\n", rc); + goto out; + } + rc = wil_up(wil); + if (rc) { + wil_err(wil, "wil_up failed (%d)\n", rc); + goto out; + } + } + + /* Wake all queues */ + if (test_bit(wil_status_fwconnected, wil->status)) + wil_update_net_queues_bh(wil, NULL, false); + +out: + if (rc) + set_bit(wil_status_suspended, wil->status); + return rc; +} + +static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) +{ + int rc = 0; + unsigned long start, data_comp_to; + + wil_dbg_pm(wil, "suspend keep radio on\n"); + + /* Prevent handling of new tx and wmi commands */ + set_bit(wil_status_suspending, wil->status); + wil_update_net_queues_bh(wil, NULL, true); + + if (!wil_is_tx_idle(wil)) { + wil_dbg_pm(wil, "Pending TX data, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + if (!wil_is_rx_idle(wil)) { + wil_dbg_pm(wil, "Pending RX data, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + if (!wil_is_wmi_idle(wil)) { + wil_dbg_pm(wil, "Pending WMI events, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + /* Send WMI suspend request to the device */ + rc = wmi_suspend(wil); + if (rc) { + wil_dbg_pm(wil, "wmi_suspend failed, reject suspend (%d)\n", + rc); + goto reject_suspend; + } + + /* Wait for completion of the pending RX packets */ + start = jiffies; + data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS); + if (test_bit(wil_status_napi_en, wil->status)) { + while (!wil_is_rx_idle(wil)) { + if (time_after(jiffies, data_comp_to)) { + if (wil_is_rx_idle(wil)) + break; + wil_err(wil, + "TO waiting for idle RX, suspend failed\n"); + wil->suspend_stats.failed_suspends++; + goto resume_after_fail; + } + wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n"); + napi_synchronize(&wil->napi_rx); + msleep(20); + } + } + + /* In case of pending WMI events, reject the suspend + * and resume the device. + * This can happen if the device sent the WMI events before + * approving the suspend. + */ + if (!wil_is_wmi_idle(wil)) { + wil_err(wil, "suspend failed due to pending WMI events\n"); + wil->suspend_stats.failed_suspends++; + goto resume_after_fail; + } + + wil_mask_irq(wil); + + /* Disable device reset on PERST */ + wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + + if (wil->platform_ops.suspend) { + rc = wil->platform_ops.suspend(wil->platform_handle, true); + if (rc) { + wil_err(wil, "platform device failed to suspend (%d)\n", + rc); + wil->suspend_stats.failed_suspends++; + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_unmask_irq(wil); + goto resume_after_fail; + } + } + + /* Save the current bus request to return to the same in resume */ + wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps; + wil6210_bus_request(wil, 0); + + set_bit(wil_status_suspended, wil->status); + clear_bit(wil_status_suspending, wil->status); + + return rc; + +resume_after_fail: + set_bit(wil_status_resuming, wil->status); + clear_bit(wil_status_suspending, wil->status); + rc = wmi_resume(wil); + /* if resume succeeded, reject the suspend */ + if (!rc) { + rc = -EBUSY; + if (test_bit(wil_status_fwconnected, wil->status)) + wil_update_net_queues_bh(wil, NULL, false); } + return rc; + +reject_suspend: + clear_bit(wil_status_suspending, wil->status); + if (test_bit(wil_status_fwconnected, wil->status)) + wil_update_net_queues_bh(wil, NULL, false); + return -EBUSY; +} + +static int wil_suspend_radio_off(struct wil6210_priv *wil) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "suspend radio off\n"); /* if netif up, hardware is alive, shut it down */ if (ndev->flags & IFF_UP) { @@ -90,7 +241,7 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) wil_disable_irq(wil); if (wil->platform_ops.suspend) { - rc = wil->platform_ops.suspend(wil->platform_handle); + rc = wil->platform_ops.suspend(wil->platform_handle, false); if (rc) { wil_enable_irq(wil); goto out; @@ -100,6 +251,50 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) set_bit(wil_status_suspended, wil->status); out: + wil_dbg_pm(wil, "suspend radio off: %d\n", rc); + + return rc; +} + +static int wil_resume_radio_off(struct wil6210_priv *wil) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); + wil_enable_irq(wil); + /* if netif up, bring hardware up + * During open(), IFF_UP set after actual device method + * invocation. This prevent recursive call to wil_up() + * wil_status_suspended will be cleared in wil_reset + */ + if (ndev->flags & IFF_UP) + rc = wil_up(wil); + else + clear_bit(wil_status_suspended, wil->status); + + return rc; +} + +int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + bool keep_radio_on = ndev->flags & IFF_UP && + wil->keep_radio_on_during_sleep; + + wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + + if (!keep_radio_on) + rc = wil_suspend_radio_off(wil); + else + rc = wil_suspend_keep_radio_on(wil); + wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); @@ -110,29 +305,24 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) { int rc = 0; struct net_device *ndev = wil_to_ndev(wil); + bool keep_radio_on = ndev->flags & IFF_UP && + wil->keep_radio_on_during_sleep; wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); if (wil->platform_ops.resume) { - rc = wil->platform_ops.resume(wil->platform_handle); + rc = wil->platform_ops.resume(wil->platform_handle, + keep_radio_on); if (rc) { wil_err(wil, "platform_ops.resume : %d\n", rc); goto out; } } - wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); - wil_enable_irq(wil); - - /* if netif up, bring hardware up - * During open(), IFF_UP set after actual device method - * invocation. This prevent recursive call to wil_up(). - * wil_status_suspended will be cleared in wil_reset - */ - if (ndev->flags & IFF_UP) - rc = wil_up(wil); + if (keep_radio_on) + rc = wil_resume_keep_radio_on(wil); else - clear_bit(wil_status_suspended, wil->status); + rc = wil_resume_radio_off(wil); out: wil_dbg_pm(wil, "resume: %s => %d\n", diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index edab4c0a900f..ec57bcce9601 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -104,6 +104,51 @@ static inline int wil_vring_avail_high(struct vring *vring) return wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring); } +/* returns true when all tx vrings are empty */ +bool wil_is_tx_idle(struct wil6210_priv *wil) +{ + int i; + unsigned long data_comp_to; + + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + struct vring *vring = &wil->vring_tx[i]; + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + + spin_lock(&txdata->lock); + + if (!vring->va || !txdata->enabled) { + spin_unlock(&txdata->lock); + continue; + } + + data_comp_to = jiffies + msecs_to_jiffies( + WIL_DATA_COMPLETION_TO_MS); + if (test_bit(wil_status_napi_en, wil->status)) { + while (!wil_vring_is_empty(vring)) { + if (time_after(jiffies, data_comp_to)) { + wil_dbg_pm(wil, + "TO waiting for idle tx\n"); + spin_unlock(&txdata->lock); + return false; + } + wil_dbg_ratelimited(wil, + "tx vring is not empty -> NAPI\n"); + spin_unlock(&txdata->lock); + napi_synchronize(&wil->napi_tx); + msleep(20); + spin_lock(&txdata->lock); + if (!vring->va || !txdata->enabled) + break; + } + } + + spin_unlock(&txdata->lock); + } + + return true; +} + /* wil_val_in_range - check if value in [min,max) */ static inline bool wil_val_in_range(int val, int min, int max) { @@ -363,7 +408,7 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, return; } - rtap_vendor = (void *)skb_push(skb, rtap_len); + rtap_vendor = skb_push(skb, rtap_len); memset(rtap_vendor, 0, rtap_len); rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION; @@ -406,6 +451,18 @@ static inline int wil_is_back_req(u8 fc) (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); } +bool wil_is_rx_idle(struct wil6210_priv *wil) +{ + struct vring_rx_desc *_d; + struct vring *vring = &wil->vring_rx; + + _d = (struct vring_rx_desc *)&vring->va[vring->swhead].rx; + if (_d->dma.status & RX_DMA_STATUS_DU) + return false; + + return true; +} + /** * reap 1 frame from @swhead * @@ -1812,6 +1869,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, spin_lock(&txdata->lock); + if (test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status) || + test_bit(wil_status_resuming, wil->status)) { + wil_dbg_txrx(wil, + "suspend/resume in progress. drop packet\n"); + spin_unlock(&txdata->lock); + return -EINVAL; + } + rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) (wil, vring, skb); @@ -1864,6 +1930,11 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, return; } + /* Do not wake the queues in suspend flow */ + if (test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status)) + return; + /* check wake */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { struct vring *cur_vring = &wil->vring_tx[i]; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b00c803a1e83..d085ccfc7228 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -37,8 +37,13 @@ extern bool debug_fw; extern bool disable_ap_sme; #define WIL_NAME "wil6210" -#define WIL_FW_NAME_DEFAULT "wil6210.fw" /* code Sparrow B0 */ -#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */ + +#define WIL_FW_NAME_DEFAULT "wil6210.fw" +#define WIL_FW_NAME_FTM_DEFAULT "wil6210_ftm.fw" + +#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" +#define WIL_FW_NAME_FTM_SPARROW_PLUS "wil6210_sparrow_plus_ftm.fw" + #define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */ #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ @@ -53,7 +58,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1); } -#define WIL6210_MEM_SIZE (2*1024*1024UL) +#define WIL6210_MIN_MEM_SIZE (2 * 1024 * 1024UL) +#define WIL6210_MAX_MEM_SIZE (4 * 1024 * 1024UL) #define WIL_TX_Q_LEN_DEFAULT (4000) #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) @@ -77,6 +83,15 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) */ #define WIL_MAX_MPDU_OVERHEAD (62) +struct wil_suspend_stats { + unsigned long successful_suspends; + unsigned long failed_suspends; + unsigned long successful_resumes; + unsigned long failed_resumes; + unsigned long rejected_by_device; + unsigned long rejected_by_host; +}; + /* Calculate MAC buffer size for the firmware. It includes all overhead, * as it will go over the air, and need to be 8 byte aligned */ @@ -284,6 +299,8 @@ enum { #define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT(1) #define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) +#define WIL_DATA_COMPLETION_TO_MS 200 + /* Hardware definitions end */ struct fw_map { u32 from; /* linker address - from, inclusive */ @@ -412,7 +429,9 @@ enum { /* for wil6210_priv.status */ wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ wil_status_resetting, /* reset in progress */ + wil_status_suspending, /* suspend in progress */ wil_status_suspended, /* suspend completed, device is suspended */ + wil_status_resuming, /* resume in progress */ wil_status_last /* keep last */ }; @@ -594,6 +613,7 @@ extern u8 led_polarity; struct wil6210_priv { struct pci_dev *pdev; + u32 bar_size; struct wireless_dev *wdev; void __iomem *csr; DECLARE_BITMAP(status, wil_status_last); @@ -676,9 +696,12 @@ struct wil6210_priv { struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; u8 discovery_mode; u8 abft_len; + u8 wakeup_trigger; + struct wil_suspend_stats suspend_stats; void *platform_handle; struct wil_platform_ops platform_ops; + bool keep_radio_on_during_sleep; struct pmc_ctx pmc; @@ -701,6 +724,11 @@ struct wil6210_priv { struct notifier_block pm_notify; #endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ + + bool suspend_resp_rcvd; + bool suspend_resp_comp; + u32 bus_request_kbps; + u32 bus_request_kbps_pre_suspend; }; #define wil_to_wiphy(i) (i->wdev->wiphy) @@ -949,7 +977,6 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil); int wil_iftype_nl2wmi(enum nl80211_iftype type); -int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); int wil_request_firmware(struct wil6210_priv *wil, const char *name, bool load); bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); @@ -957,6 +984,11 @@ bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_resume(struct wil6210_priv *wil, bool is_runtime); +bool wil_is_wmi_idle(struct wil6210_priv *wil); +int wmi_resume(struct wil6210_priv *wil); +int wmi_suspend(struct wil6210_priv *wil); +bool wil_is_tx_idle(struct wil6210_priv *wil); +bool wil_is_rx_idle(struct wil6210_priv *wil); int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size); void wil_fw_core_dump(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index f8c41172a3f4..5d9e4bfcb045 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,10 +33,11 @@ enum wil_platform_event { */ struct wil_platform_ops { int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */); - int (*suspend)(void *handle); - int (*resume)(void *handle); + int (*suspend)(void *handle, bool keep_device_power); + int (*resume)(void *handle, bool device_powered_on); void (*uninit)(void *handle); int (*notify)(void *handle, enum wil_platform_event evt); + bool (*keep_radio_on_during_sleep)(void *handle); }; /** diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 814c35645b73..65ef67321fc0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -37,6 +37,8 @@ module_param(led_id, byte, 0444); MODULE_PARM_DESC(led_id, " 60G device led enablement. Set the led ID (0-2) to enable"); +#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200 + /** * WMI event receiving - theory of operations * @@ -157,7 +159,7 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) return NULL; off = HOSTADDR(ptr); - if (off > WIL6210_MEM_SIZE - 4) + if (off > wil->bar_size - 4) return NULL; return wil->csr + off; @@ -177,7 +179,7 @@ void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr) return NULL; off = HOSTADDR(ptr); - if (off > WIL6210_MEM_SIZE - 4) + if (off > wil->bar_size - 4) return NULL; return wil->csr + off; @@ -233,6 +235,16 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) return -EAGAIN; } + /* Allow sending only suspend / resume commands during susepnd flow */ + if ((test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status) || + test_bit(wil_status_resuming, wil->status)) && + ((cmdid != WMI_TRAFFIC_SUSPEND_CMDID) && + (cmdid != WMI_TRAFFIC_RESUME_CMDID))) { + wil_err(wil, "WMI: reject send_command during suspend\n"); + return -EINVAL; + } + if (!head) { wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head); return -EINVAL; @@ -677,11 +689,11 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, return; } - eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); + eth = skb_put(skb, ETH_HLEN); ether_addr_copy(eth->h_dest, ndev->dev_addr); ether_addr_copy(eth->h_source, evt->src_mac); eth->h_proto = cpu_to_be16(ETH_P_PAE); - memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len); + skb_put_data(skb, evt->eapol, eapol_len); skb->protocol = eth_type_trans(skb, ndev); if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { ndev->stats.rx_packets++; @@ -862,6 +874,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) return; } + if (test_bit(wil_status_suspended, wil->status)) { + wil_err(wil, "suspended. cannot handle WMI event\n"); + return; + } + for (n = 0;; n++) { u16 len; bool q; @@ -914,6 +931,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil) struct wmi_cmd_hdr *wmi = &evt->event.wmi; u16 id = le16_to_cpu(wmi->command_id); u32 tstamp = le32_to_cpu(wmi->fw_timestamp); + if (test_bit(wil_status_resuming, wil->status)) { + if (id == WMI_TRAFFIC_RESUME_EVENTID) + clear_bit(wil_status_resuming, + wil->status); + else + wil_err(wil, + "WMI evt %d while resuming\n", + id); + } spin_lock_irqsave(&wil->wmi_ev_lock, flags); if (wil->reply_id && wil->reply_id == id) { if (wil->reply_buf) { @@ -921,6 +947,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) min(len, wil->reply_size)); immed_reply = true; } + if (id == WMI_TRAFFIC_SUSPEND_EVENTID) { + wil_dbg_wmi(wil, + "set suspend_resp_rcvd\n"); + wil->suspend_resp_rcvd = true; + } } spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); @@ -1762,6 +1793,85 @@ void wmi_event_flush(struct wil6210_priv *wil) spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); } +int wmi_suspend(struct wil6210_priv *wil) +{ + int rc; + struct wmi_traffic_suspend_cmd cmd = { + .wakeup_trigger = wil->wakeup_trigger, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_traffic_suspend_event evt; + } __packed reply; + u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP; + + wil->suspend_resp_rcvd = false; + wil->suspend_resp_comp = false; + + reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED; + + rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd), + WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply), + suspend_to); + if (rc) { + wil_err(wil, "wmi_call for suspend req failed, rc=%d\n", rc); + if (rc == -ETIME) + /* wmi_call TO */ + wil->suspend_stats.rejected_by_device++; + else + wil->suspend_stats.rejected_by_host++; + goto out; + } + + wil_dbg_wmi(wil, "waiting for suspend_response_completed\n"); + + rc = wait_event_interruptible_timeout(wil->wq, + wil->suspend_resp_comp, + msecs_to_jiffies(suspend_to)); + if (rc == 0) { + wil_err(wil, "TO waiting for suspend_response_completed\n"); + if (wil->suspend_resp_rcvd) + /* Device responded but we TO due to another reason */ + wil->suspend_stats.rejected_by_host++; + else + wil->suspend_stats.rejected_by_device++; + rc = -EBUSY; + goto out; + } + + wil_dbg_wmi(wil, "suspend_response_completed rcvd\n"); + if (reply.evt.status == WMI_TRAFFIC_SUSPEND_REJECTED) { + wil_dbg_pm(wil, "device rejected the suspend\n"); + wil->suspend_stats.rejected_by_device++; + } + rc = reply.evt.status; + +out: + wil->suspend_resp_rcvd = false; + wil->suspend_resp_comp = false; + + return rc; +} + +int wmi_resume(struct wil6210_priv *wil) +{ + int rc; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_traffic_resume_event evt; + } __packed reply; + + reply.evt.status = WMI_TRAFFIC_RESUME_FAILED; + + rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0, + WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply), + WIL_WAIT_FOR_SUSPEND_RESUME_COMP); + if (rc) + return rc; + + return reply.evt.status; +} + static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, void *d, int len) { @@ -1851,3 +1961,36 @@ void wmi_event_worker(struct work_struct *work) } wil_dbg_wmi(wil, "event_worker: Finished\n"); } + +bool wil_is_wmi_idle(struct wil6210_priv *wil) +{ + ulong flags; + struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx; + bool rc = false; + + spin_lock_irqsave(&wil->wmi_ev_lock, flags); + + /* Check if there are pending WMI events in the events queue */ + if (!list_empty(&wil->pending_wmi_ev)) { + wil_dbg_pm(wil, "Pending WMI events in queue\n"); + goto out; + } + + /* Check if there is a pending WMI call */ + if (wil->reply_id) { + wil_dbg_pm(wil, "Pending WMI call\n"); + goto out; + } + + /* Check if there are pending RX events in mbox */ + r->head = wil_r(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, rx.head)); + if (r->tail != r->head) + wil_dbg_pm(wil, "Pending WMI mbox events\n"); + else + rc = true; + +out: + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index f7f5f4f801e3..256f63c57da0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -59,6 +59,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, WMI_FW_CAPABILITY_WMI_ONLY = 5, WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, + WMI_FW_CAPABILITY_D3_SUSPEND = 8, WMI_FW_CAPABILITY_MAX, }; @@ -157,7 +158,7 @@ enum wmi_command_id { WMI_FLASH_READ_CMDID = 0x902, WMI_FLASH_WRITE_CMDID = 0x903, /* Power management */ - WMI_TRAFFIC_DEFERRAL_CMDID = 0x904, + WMI_TRAFFIC_SUSPEND_CMDID = 0x904, WMI_TRAFFIC_RESUME_CMDID = 0x905, /* P2P */ WMI_P2P_CFG_CMDID = 0x910, @@ -500,8 +501,14 @@ struct wmi_port_delete_cmd { u8 reserved[3]; } __packed; -/* WMI_TRAFFIC_DEFERRAL_CMDID */ -struct wmi_traffic_deferral_cmd { +/* WMI_TRAFFIC_SUSPEND_CMD wakeup trigger bit mask values */ +enum wmi_wakeup_trigger { + WMI_WAKEUP_TRIGGER_UCAST = 0x01, + WMI_WAKEUP_TRIGGER_BCAST = 0x02, +}; + +/* WMI_TRAFFIC_SUSPEND_CMDID */ +struct wmi_traffic_suspend_cmd { /* Bit vector: bit[0] - wake on Unicast, bit[1] - wake on Broadcast */ u8 wakeup_trigger; } __packed; @@ -1084,7 +1091,7 @@ enum wmi_event_id { WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, /* Power management */ - WMI_TRAFFIC_DEFERRAL_EVENTID = 0x1904, + WMI_TRAFFIC_SUSPEND_EVENTID = 0x1904, WMI_TRAFFIC_RESUME_EVENTID = 0x1905, /* P2P */ WMI_P2P_CFG_DONE_EVENTID = 0x1910, @@ -1926,14 +1933,14 @@ struct wmi_link_maintain_cfg_read_done_event { struct wmi_link_maintain_cfg lm_cfg; } __packed; -enum wmi_traffic_deferral_status { - WMI_TRAFFIC_DEFERRAL_APPROVED = 0x0, - WMI_TRAFFIC_DEFERRAL_REJECTED = 0x1, +enum wmi_traffic_suspend_status { + WMI_TRAFFIC_SUSPEND_APPROVED = 0x0, + WMI_TRAFFIC_SUSPEND_REJECTED = 0x1, }; -/* WMI_TRAFFIC_DEFERRAL_EVENTID */ -struct wmi_traffic_deferral_event { - /* enum wmi_traffic_deferral_status_e */ +/* WMI_TRAFFIC_SUSPEND_EVENTID */ +struct wmi_traffic_suspend_event { + /* enum wmi_traffic_suspend_status_e */ u8 status; } __packed; diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c index 27b110dc8cc6..b68436b23a63 100644 --- a/drivers/net/wireless/atmel/atmel.c +++ b/drivers/net/wireless/atmel/atmel.c @@ -1036,9 +1036,8 @@ static void frag_rx_path(struct atmel_private *priv, priv->dev->stats.rx_dropped++; } else { skb_reserve(skb, 2); - memcpy(skb_put(skb, priv->frag_len + 12), - priv->rx_buf, - priv->frag_len + 12); + skb_put_data(skb, priv->rx_buf, + priv->frag_len + 12); skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index d23aac7503d3..b37e7391f55d 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -71,8 +71,18 @@ MODULE_FIRMWARE("b43/ucode11.fw"); MODULE_FIRMWARE("b43/ucode13.fw"); MODULE_FIRMWARE("b43/ucode14.fw"); MODULE_FIRMWARE("b43/ucode15.fw"); +MODULE_FIRMWARE("b43/ucode16_lp.fw"); MODULE_FIRMWARE("b43/ucode16_mimo.fw"); +MODULE_FIRMWARE("b43/ucode24_lcn.fw"); +MODULE_FIRMWARE("b43/ucode25_lcn.fw"); +MODULE_FIRMWARE("b43/ucode25_mimo.fw"); +MODULE_FIRMWARE("b43/ucode26_mimo.fw"); +MODULE_FIRMWARE("b43/ucode29_mimo.fw"); +MODULE_FIRMWARE("b43/ucode33_lcn40.fw"); +MODULE_FIRMWARE("b43/ucode30_mimo.fw"); MODULE_FIRMWARE("b43/ucode5.fw"); +MODULE_FIRMWARE("b43/ucode40.fw"); +MODULE_FIRMWARE("b43/ucode42.fw"); MODULE_FIRMWARE("b43/ucode9.fw"); static int modparam_bad_frames_preempt; diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c index f9dd892b9f27..cfa617ddb2f1 100644 --- a/drivers/net/wireless/broadcom/b43legacy/dma.c +++ b/drivers/net/wireless/broadcom/b43legacy/dma.c @@ -1072,7 +1072,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, goto out_unmap_hdr; } - memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + skb_put_data(bounce_skb, skb->data, skb->len); memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb)); bounce_skb->dev = skb->dev; skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb)); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 9b970dc2b922..984c1d0560b1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -108,12 +108,14 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) int ret = 0; u8 data; u32 addr, gpiocontrol; - unsigned long flags; pdata = &sdiodev->settings->bus.sdio; if (pdata->oob_irq_supported) { brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n", pdata->oob_irq_nr); + spin_lock_init(&sdiodev->irq_en_lock); + sdiodev->irq_en = true; + ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler, pdata->oob_irq_flags, "brcmf_oob_intr", &sdiodev->func[1]->dev); @@ -122,10 +124,6 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) return ret; } sdiodev->oob_irq_requested = true; - spin_lock_init(&sdiodev->irq_en_lock); - spin_lock_irqsave(&sdiodev->irq_en_lock, flags); - sdiodev->irq_en = true; - spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags); ret = enable_irq_wake(pdata->oob_irq_nr); if (ret != 0) { @@ -706,7 +704,7 @@ done: int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, struct sk_buff_head *pktq, uint totlen) { - struct sk_buff *glom_skb; + struct sk_buff *glom_skb = NULL; struct sk_buff *skb; u32 addr = sdiodev->sbwad; int err = 0; @@ -727,10 +725,8 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, return -ENOMEM; err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, glom_skb); - if (err) { - brcmu_pkt_buf_free_skb(glom_skb); + if (err) goto done; - } skb_queue_walk(pktq, skb) { memcpy(skb->data, glom_skb->data, skb->len); @@ -741,6 +737,7 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, pktq); done: + brcmu_pkt_buf_free_skb(glom_skb); return err; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c index 14a70d4b4e86..3559fb5b8fb0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c @@ -380,9 +380,7 @@ int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg) /* Set up timer for BT */ btci->timer_on = false; btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME; - init_timer(&btci->timer); - btci->timer.data = (ulong)btci; - btci->timer.function = brcmf_btcoex_timerfunc; + setup_timer(&btci->timer, brcmf_btcoex_timerfunc, (ulong)btci); btci->cfg = cfg; btci->saved_regs_part1 = false; btci->saved_regs_part2 = false; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index b55c3293c4b4..163ddc49f951 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -113,6 +113,17 @@ struct brcmf_bus_msgbuf { /** + * struct brcmf_bus_stats - bus statistic counters. + * + * @pktcowed: packets cowed for extra headroom/unorphan. + * @pktcow_failed: packets dropped due to failed cow-ing. + */ +struct brcmf_bus_stats { + atomic_t pktcowed; + atomic_t pktcow_failed; +}; + +/** * struct brcmf_bus - interface structure between common and bus layer * * @bus_priv: pointer to private bus device. @@ -120,11 +131,10 @@ struct brcmf_bus_msgbuf { * @dev: device pointer of bus device. * @drvr: public driver information. * @state: operational state of the bus interface. + * @stats: statistics shared between common and bus layer. * @maxctl: maximum size for rxctl request message. - * @tx_realloc: number of tx packets realloced for headroom. - * @dstats: dongle-based statistical data. - * @dcmd_list: bus/device specific dongle initialization commands. * @chip: device identifier of the dongle chip. + * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive. * @wowl_supported: is wowl supported by bus driver. * @chiprev: revision of the dongle chip. */ @@ -138,8 +148,8 @@ struct brcmf_bus { struct device *dev; struct brcmf_pub *drvr; enum brcmf_bus_state state; + struct brcmf_bus_stats stats; uint maxctl; - unsigned long tx_realloc; u32 chip; u32 chiprev; bool always_use_fws_queue; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 617199c0e5a0..dcde596c9eb9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -625,6 +625,7 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, err = brcmf_net_attach(ifp, true); if (err) { brcmf_err("Registering netdevice failed\n"); + free_netdev(ifp->ndev); goto fail; } @@ -719,6 +720,8 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, { struct brcmf_scan_params_le params_le; struct cfg80211_scan_request *scan_request; + u64 reqid; + u32 bucket; s32 err = 0; brcmf_dbg(SCAN, "Enter\n"); @@ -749,7 +752,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, ¶ms_le, sizeof(params_le)); if (err) - brcmf_err("Scan abort failed\n"); + brcmf_err("Scan abort failed\n"); } brcmf_scan_config_mpc(ifp, 1); @@ -758,11 +761,21 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, * e-scan can be initiated internally * which takes precedence. */ - if (cfg->internal_escan) { - brcmf_dbg(SCAN, "scheduled scan completed\n"); - cfg->internal_escan = false; - if (!aborted) - cfg80211_sched_scan_results(cfg_to_wiphy(cfg), 0); + if (cfg->int_escan_map) { + brcmf_dbg(SCAN, "scheduled scan completed (%x)\n", + cfg->int_escan_map); + while (cfg->int_escan_map) { + bucket = __ffs(cfg->int_escan_map); + cfg->int_escan_map &= ~BIT(bucket); + reqid = brcmf_pno_find_reqid_by_bucket(cfg->pno, + bucket); + if (!aborted) { + brcmf_dbg(SCAN, "report results: reqid=%llu\n", + reqid); + cfg80211_sched_scan_results(cfg_to_wiphy(cfg), + reqid); + } + } } else if (scan_request) { struct cfg80211_scan_info info = { .aborted = aborted, @@ -1011,7 +1024,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, if (!ssid_le.SSID_len) brcmf_dbg(SCAN, "%d: Broadcast scan\n", i); else - brcmf_dbg(SCAN, "%d: scan for %s size =%d\n", + brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n", i, ssid_le.SSID, ssid_le.SSID_len); memcpy(ptr, &ssid_le, sizeof(ssid_le)); ptr += sizeof(ssid_le); @@ -1344,6 +1357,27 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) return reason; } +static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) +{ + struct brcmf_wsec_pmk_le pmk; + int i, err; + + /* convert to firmware key format */ + pmk.key_len = cpu_to_le16(pmk_len << 1); + pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE); + for (i = 0; i < pmk_len; i++) + snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]); + + /* store psk in firmware */ + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, + &pmk, sizeof(pmk)); + if (err < 0) + brcmf_err("failed to change PSK in firmware (len=%u)\n", + pmk_len); + + return err; +} + static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); @@ -1366,6 +1400,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0); + if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { + brcmf_set_pmk(vif->ifp, NULL, 0); + vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + } brcmf_dbg(TRACE, "Exit\n"); } @@ -1679,6 +1717,7 @@ static s32 brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) { struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; s32 val; s32 err; const struct brcmf_tlv *rsn_ie; @@ -1689,6 +1728,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) u32 mfp; u16 count; + profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + if (!sme->crypto.n_akm_suites) return 0; @@ -1701,6 +1742,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_8021X: val = WPA_AUTH_UNSPECIFIED; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_PSK: val = WPA_AUTH_PSK; @@ -1714,9 +1757,13 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_8021X: val = WPA2_AUTH_UNSPECIFIED; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_8021X_SHA256: val = WPA2_AUTH_1X_SHA256; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_PSK_SHA256: val = WPA2_AUTH_PSK_SHA256; @@ -1731,6 +1778,9 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) } } + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X) + brcmf_dbg(INFO, "using 1X offload\n"); + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) goto skip_mfp_config; /* The MFP mode (1 or 2) needs to be determined, parse IEs. The @@ -1903,6 +1953,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct ieee80211_channel *chan = sme->channel; struct brcmf_join_params join_params; size_t join_params_size; @@ -1999,6 +2050,31 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } + if (sme->crypto.psk) { + if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) { + err = -EINVAL; + goto done; + } + brcmf_dbg(INFO, "using PSK offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK; + } + + if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { + /* enable firmware supplicant for this interface */ + err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); + if (err < 0) { + brcmf_err("failed to enable fw supplicant\n"); + goto done; + } + } + + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { + err = brcmf_set_pmk(ifp, sme->crypto.psk, + BRCMF_WSEC_MAX_PSK_LEN); + if (err) + goto done; + } + /* Join with specific BSSID and cached SSID * If SSID is zero join based on BSSID only */ @@ -3011,7 +3087,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) struct escan_info *escan = &cfg->escan_info; set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); - if (cfg->internal_escan || cfg->scan_request) { + if (cfg->int_escan_map || cfg->scan_request) { escan->escan_state = WL_ESCAN_STATE_IDLE; brcmf_notify_escan_complete(cfg, escan->ifp, true, true); } @@ -3034,7 +3110,7 @@ static void brcmf_escan_timeout(unsigned long data) struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)data; - if (cfg->internal_escan || cfg->scan_request) { + if (cfg->int_escan_map || cfg->scan_request) { brcmf_err("timer expired\n"); schedule_work(&cfg->escan_timeout_work); } @@ -3120,7 +3196,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) goto exit; - if (!cfg->internal_escan && !cfg->scan_request) { + if (!cfg->int_escan_map && !cfg->scan_request) { brcmf_dbg(SCAN, "result without cfg80211 request\n"); goto exit; } @@ -3166,7 +3242,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) goto exit; - if (cfg->internal_escan || cfg->scan_request) { + if (cfg->int_escan_map || cfg->scan_request) { brcmf_inform_bss(cfg); aborted = status != BRCMF_E_STATUS_SUCCESS; brcmf_notify_escan_complete(cfg, ifp, aborted, false); @@ -3248,17 +3324,21 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req, return 0; } -static int brcmf_start_internal_escan(struct brcmf_if *ifp, +static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap, struct cfg80211_scan_request *request) { struct brcmf_cfg80211_info *cfg = ifp->drvr->config; int err; if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + if (cfg->int_escan_map) + brcmf_dbg(SCAN, "aborting internal scan: map=%u\n", + cfg->int_escan_map); /* Abort any on-going scan */ brcmf_abort_scanning(cfg); } + brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap); set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); cfg->escan_info.run = brcmf_run_escan; err = brcmf_do_escan(ifp, request); @@ -3266,7 +3346,7 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp, clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); return err; } - cfg->internal_escan = true; + cfg->int_escan_map = fwmap; return 0; } @@ -3308,6 +3388,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, struct wiphy *wiphy = cfg_to_wiphy(cfg); int i, err = 0; struct brcmf_pno_scanresults_le *pfn_result; + u32 bucket_map; u32 result_count; u32 status; u32 datalen; @@ -3352,6 +3433,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, goto out_err; } + bucket_map = 0; for (i = 0; i < result_count; i++) { netinfo = &netinfo_start[i]; @@ -3359,6 +3441,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, netinfo->SSID_len = IEEE80211_MAX_SSID_LEN; brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n", netinfo->SSID, netinfo->channel); + bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo); err = brcmf_internal_escan_add_info(request, netinfo->SSID, netinfo->SSID_len, @@ -3367,7 +3450,10 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, goto out_err; } - err = brcmf_start_internal_escan(ifp, request); + if (!bucket_map) + goto free_req; + + err = brcmf_start_internal_escan(ifp, bucket_map, request); if (!err) goto free_req; @@ -3386,11 +3472,11 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); - brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n", + brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n", req->n_match_sets, req->n_ssids); if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) { - brcmf_err("Scanning suppressed: status (%lu)\n", + brcmf_err("Scanning suppressed: status=%lu\n", cfg->scan_status); return -EAGAIN; } @@ -3411,8 +3497,8 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct brcmf_if *ifp = netdev_priv(ndev); brcmf_dbg(SCAN, "enter\n"); - brcmf_pno_clean(ifp); - if (cfg->internal_escan) + brcmf_pno_stop_sched_scan(ifp, reqid); + if (cfg->int_escan_map) brcmf_notify_escan_complete(cfg, ifp, true, true); return 0; } @@ -4674,9 +4760,6 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); if (err < 0) brcmf_err("setting AP mode failed %d\n", err); - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); - if (err < 0) - brcmf_err("setting INFRA mode failed %d\n", err); if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) brcmf_fil_iovar_int_set(ifp, "mbss", 0); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, @@ -5131,6 +5214,34 @@ brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev, } #endif +static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev, + const struct cfg80211_pmk_conf *conf) +{ + struct brcmf_if *ifp; + + brcmf_dbg(TRACE, "enter\n"); + + /* expect using firmware supplicant for 1X */ + ifp = netdev_priv(dev); + if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X)) + return -EINVAL; + + return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len); +} + +static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, + const u8 *aa) +{ + struct brcmf_if *ifp; + + brcmf_dbg(TRACE, "enter\n"); + ifp = netdev_priv(dev); + if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X)) + return -EINVAL; + + return brcmf_set_pmk(ifp, NULL, 0); +} + static struct cfg80211_ops brcmf_cfg80211_ops = { .add_virtual_intf = brcmf_cfg80211_add_iface, .del_virtual_intf = brcmf_cfg80211_del_iface, @@ -5174,6 +5285,8 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .crit_proto_stop = brcmf_cfg80211_crit_proto_stop, .tdls_oper = brcmf_cfg80211_tdls_oper, .update_connect_params = brcmf_cfg80211_update_conn_params, + .set_pmk = brcmf_cfg80211_set_pmk, + .del_pmk = brcmf_cfg80211_del_pmk, }; struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, @@ -5227,16 +5340,31 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev) brcmf_free_vif(vif); } -static bool brcmf_is_linkup(const struct brcmf_event_msg *e) +static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, + const struct brcmf_event_msg *e) { u32 event = e->event_code; u32 status = e->status; + if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK && + event == BRCMF_E_PSK_SUP && + status == BRCMF_E_STATUS_FWSUP_COMPLETED) + set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { brcmf_dbg(CONN, "Processing set ssid\n"); - return true; + memcpy(vif->profile.bssid, e->addr, ETH_ALEN); + if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK) + return true; + + set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); } + if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) && + test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) { + clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); + clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); + return true; + } return false; } @@ -5271,6 +5399,13 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg, return true; } + if (event == BRCMF_E_PSK_SUP && + status != BRCMF_E_STATUS_FWSUP_COMPLETED) { + brcmf_dbg(CONN, "Processing failed supplicant state: %u\n", + status); + return true; + } + return false; } @@ -5421,27 +5556,28 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + struct cfg80211_connect_resp_params conn_params; brcmf_dbg(TRACE, "Enter\n"); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { + memset(&conn_params, 0, sizeof(conn_params)); if (completed) { brcmf_get_assoc_ies(cfg, ifp); - memcpy(profile->bssid, e->addr, ETH_ALEN); brcmf_update_bss_info(cfg, ifp); set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); + conn_params.status = WLAN_STATUS_SUCCESS; + } else { + conn_params.status = WLAN_STATUS_AUTH_TIMEOUT; } - cfg80211_connect_result(ndev, - (u8 *)profile->bssid, - conn_info->req_ie, - conn_info->req_ie_len, - conn_info->resp_ie, - conn_info->resp_ie_len, - completed ? WLAN_STATUS_SUCCESS : - WLAN_STATUS_AUTH_TIMEOUT, - GFP_KERNEL); + conn_params.bssid = profile->bssid; + conn_params.req_ie = conn_info->req_ie; + conn_params.req_ie_len = conn_info->req_ie_len; + conn_params.resp_ie = conn_info->resp_ie; + conn_params.resp_ie_len = conn_info->resp_ie_len; + cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL); brcmf_dbg(CONN, "Report connect result - connection %s\n", completed ? "succeeded" : "failed"); } @@ -5507,7 +5643,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, if (brcmf_is_apmode(ifp->vif)) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); - } else if (brcmf_is_linkup(e)) { + } else if (brcmf_is_linkup(ifp->vif, e)) { brcmf_dbg(CONN, "Linkup\n"); if (brcmf_is_ibssmode(ifp->vif)) { brcmf_inform_ibss(cfg, ndev, e->addr); @@ -5675,6 +5811,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) brcmf_p2p_notify_action_tx_complete); brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, brcmf_p2p_notify_action_tx_complete); + brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP, + brcmf_notify_connect_status); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) @@ -6377,16 +6515,6 @@ err: return -ENOMEM; } -static void brcmf_wiphy_pno_params(struct wiphy *wiphy) -{ - /* scheduled scan settings */ - wiphy->max_sched_scan_reqs = 1; - wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; - wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; - wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; - wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; -} - #ifdef CONFIG_PM static const struct wiphy_wowlan_support brcmf_wowlan_support = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -6433,6 +6561,7 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) const struct ieee80211_iface_combination *combo; struct ieee80211_supported_band *band; u16 max_interfaces = 0; + bool gscan; __le32 bandlist[3]; u32 n_bands; int err, i; @@ -6480,11 +6609,18 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; if (!ifp->drvr->settings->roamoff) wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) { + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); + } wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) - brcmf_wiphy_pno_params(wiphy); - + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { + gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN); + brcmf_pno_wiphy_params(wiphy, gscan); + } /* vendor commands/events support */ wiphy->vendor_commands = brcmf_vendor_cmds; wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1; @@ -6766,7 +6902,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, /* ignore non-ISO3166 country codes */ for (i = 0; i < sizeof(req->alpha2); i++) if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { - brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n", + brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n", req->alpha2[0], req->alpha2[1]); return; } @@ -6850,7 +6986,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info)); if (!wiphy) { brcmf_err("Could not allocate wiphy device\n"); - return NULL; + goto ops_out; } memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN); set_wiphy_dev(wiphy, busdev); @@ -6951,6 +7087,13 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, brcmf_p2p_detach(&cfg->p2p); goto wiphy_unreg_out; } + err = brcmf_pno_attach(cfg); + if (err) { + brcmf_err("PNO initialisation failed (%d)\n", err); + brcmf_btcoex_detach(cfg); + brcmf_p2p_detach(&cfg->p2p); + goto wiphy_unreg_out; + } if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) { err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); @@ -6983,6 +7126,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, return cfg; detach: + brcmf_pno_detach(cfg); brcmf_btcoex_detach(cfg); brcmf_p2p_detach(&cfg->p2p); wiphy_unreg_out: @@ -6993,6 +7137,7 @@ priv_out: ifp->vif = NULL; wiphy_out: brcmf_free_wiphy(wiphy); +ops_out: kfree(ops); return NULL; } @@ -7002,6 +7147,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) if (!cfg) return; + brcmf_pno_detach(cfg); brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); kfree(cfg->ops); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 8f19d95d4175..7b2835e5e434 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -24,6 +24,8 @@ #include "fwil_types.h" #include "p2p.h" +#define BRCMF_SCAN_IE_LEN_MAX 2048 + #define WL_NUM_SCAN_MAX 10 #define WL_TLV_INFO_MAX 1024 #define WL_BSS_INFO_MAX 2048 @@ -113,6 +115,12 @@ struct brcmf_cfg80211_security { u32 cipher_group; }; +enum brcmf_profile_fwsup { + BRCMF_PROFILE_FWSUP_NONE, + BRCMF_PROFILE_FWSUP_PSK, + BRCMF_PROFILE_FWSUP_1X +}; + /** * struct brcmf_cfg80211_profile - profile information. * @@ -124,6 +132,7 @@ struct brcmf_cfg80211_profile { u8 bssid[ETH_ALEN]; struct brcmf_cfg80211_security sec; struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS]; + enum brcmf_profile_fwsup use_fwsup; }; /** @@ -131,16 +140,20 @@ struct brcmf_cfg80211_profile { * * @BRCMF_VIF_STATUS_READY: ready for operation. * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. - * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. + * @BRCMF_VIF_STATUS_CONNECTED: connected/joined successfully. * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress. * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. + * @BRCMF_VIF_STATUS_EAP_SUCCUSS: EAPOL handshake successful. + * @BRCMF_VIF_STATUS_ASSOC_SUCCESS: successful SET_SSID received. */ enum brcmf_vif_status { BRCMF_VIF_STATUS_READY, BRCMF_VIF_STATUS_CONNECTING, BRCMF_VIF_STATUS_CONNECTED, BRCMF_VIF_STATUS_DISCONNECTING, - BRCMF_VIF_STATUS_AP_CREATED + BRCMF_VIF_STATUS_AP_CREATED, + BRCMF_VIF_STATUS_EAP_SUCCESS, + BRCMF_VIF_STATUS_ASSOC_SUCCESS, }; /** @@ -271,7 +284,7 @@ struct brcmf_cfg80211_wowl { * @pub: common driver information. * @channel: current channel. * @active_scan: current scan mode. - * @internal_escan: indicates internally initiated e-scan is running. + * @int_escan_map: bucket map for which internal e-scan is done. * @ibss_starter: indicates this sta is ibss starter. * @pwr_save: indicate whether dongle to support power save mode. * @dongle_up: indicate whether dongle up or not. @@ -287,6 +300,7 @@ struct brcmf_cfg80211_wowl { * @vif_cnt: number of vif instances. * @vif_event: vif event signalling. * @wowl: wowl related information. + * @pno: information of pno module. */ struct brcmf_cfg80211_info { struct wiphy *wiphy; @@ -303,7 +317,7 @@ struct brcmf_cfg80211_info { struct brcmf_pub *pub; u32 channel; bool active_scan; - bool internal_escan; + u32 int_escan_map; bool ibss_starter; bool pwr_save; bool dongle_up; @@ -320,6 +334,7 @@ struct brcmf_cfg80211_info { struct brcmu_d11inf d11inf; struct brcmf_assoclist_le assoclist; struct brcmf_cfg80211_wowl wowl; + struct brcmf_pno_info *pno; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 511d190c6cca..2153e8062b4c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -30,6 +30,7 @@ #include "debug.h" #include "fwil_types.h" #include "p2p.h" +#include "pno.h" #include "cfg80211.h" #include "fwil.h" #include "feature.h" @@ -198,6 +199,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; struct ethhdr *eh; + int head_delta; brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx); @@ -210,13 +212,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, goto done; } - /* Make sure there's enough writable headroom*/ - ret = skb_cow_head(skb, drvr->hdrlen); - if (ret < 0) { - brcmf_err("%s: skb_cow_head failed\n", - brcmf_ifname(ifp)); - dev_kfree_skb(skb); - goto done; + /* Make sure there's enough writeable headroom */ + if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) { + head_delta = drvr->hdrlen - skb_headroom(skb); + + brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n", + brcmf_ifname(ifp), head_delta); + atomic_inc(&drvr->bus_if->stats.pktcowed); + ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0, + GFP_ATOMIC); + if (ret < 0) { + brcmf_err("%s: failed to expand headroom\n", + brcmf_ifname(ifp)); + atomic_inc(&drvr->bus_if->stats.pktcow_failed); + goto done; + } } /* validate length for ether packet */ @@ -484,13 +494,13 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) goto fail; } + ndev->priv_destructor = brcmf_cfg80211_free_netdev; brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); return 0; fail: drvr->iflist[ifp->bsscfgidx] = NULL; ndev->netdev_ops = NULL; - free_netdev(ndev); return -EBADE; } @@ -503,6 +513,7 @@ static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) unregister_netdev(ndev); } else { brcmf_cfg80211_free_netdev(ndev); + free_netdev(ndev); } } @@ -579,7 +590,6 @@ static int brcmf_net_p2p_attach(struct brcmf_if *ifp) fail: ifp->drvr->iflist[ifp->bsscfgidx] = NULL; ndev->netdev_ops = NULL; - free_netdev(ndev); return -EBADE; } @@ -625,7 +635,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, return ERR_PTR(-ENOMEM); ndev->needs_free_netdev = true; - ndev->priv_destructor = brcmf_cfg80211_free_netdev; ifp = netdev_priv(ndev); ifp->ndev = ndev; /* store mapping ifidx to bsscfgidx */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h index fe264a5798f1..35919d9e8e13 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h @@ -78,6 +78,7 @@ do { \ #define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL) #define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL) #define BRCMF_FWCON_ON() (brcmf_msg_level & BRCMF_FWCON_VAL) +#define BRCMF_SCAN_ON() (brcmf_msg_level & BRCMF_SCAN_VAL) #else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */ @@ -96,6 +97,7 @@ do { \ #define BRCMF_EVENT_ON() 0 #define BRCMF_FIL_ON() 0 #define BRCMF_FWCON_ON() 0 +#define BRCMF_SCAN_ON() 0 #endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 62985f2c0853..d21258d277ce 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -27,6 +27,7 @@ #include "feature.h" #include "common.h" +#define BRCMF_FW_UNSUPPORTED 23 /* * expand feature list to array of feature strings. @@ -113,6 +114,22 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, } } +static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp, + enum brcmf_feat_id id, char *name, + const void *data, size_t len) +{ + int err; + + err = brcmf_fil_iovar_data_set(ifp, name, data, len); + if (err != -BRCMF_FW_UNSUPPORTED) { + brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); + ifp->drvr->feat_flags |= BIT(id); + } else { + brcmf_dbg(TRACE, "%s feature check failed: %d\n", + brcmf_feat_names[id], err); + } +} + static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp) { char caps[256]; @@ -136,11 +153,14 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) { struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); struct brcmf_pno_macaddr_le pfn_mac; + struct brcmf_gscan_config gscan_cfg; u32 wowl_cap; s32 err; brcmf_feat_firmware_capabilities(ifp); - + memset(&gscan_cfg, 0, sizeof(gscan_cfg)); + brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN, "pfn_gscan_cfg", + &gscan_cfg, sizeof(gscan_cfg)); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); if (drvr->bus_if->wowl_supported) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); @@ -175,6 +195,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) drvr->settings->feature_disable); ifp->drvr->feat_flags &= ~drvr->settings->feature_disable; } + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); /* set chip related quirks */ switch (drvr->bus_if->chip) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index db4733a95e28..1ab4f1617112 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -31,6 +31,8 @@ * WOWL_GTK: (WOWL) GTK rekeying offload * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL. * MFP: 802.11w Management Frame Protection. + * GSCAN: enhanced scan offload feature. + * FWSUP: Firmware supplicant. */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -44,7 +46,9 @@ BRCMF_FEAT_DEF(WOWL_ND) \ BRCMF_FEAT_DEF(WOWL_GTK) \ BRCMF_FEAT_DEF(WOWL_ARP_ND) \ - BRCMF_FEAT_DEF(MFP) + BRCMF_FEAT_DEF(MFP) \ + BRCMF_FEAT_DEF(GSCAN) \ + BRCMF_FEAT_DEF(FWSUP) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 5fba4b49f3b3..816f80ea925b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -142,6 +142,16 @@ enum brcmf_fweh_event_code { #define BRCMF_E_STATUS_CS_ABORT 15 #define BRCMF_E_STATUS_ERROR 16 +/* status field values for PSK_SUP event */ +#define BRCMF_E_STATUS_FWSUP_WAIT_M1 4 +#define BRCMF_E_STATUS_FWSUP_PREP_M2 5 +#define BRCMF_E_STATUS_FWSUP_COMPLETED 6 +#define BRCMF_E_STATUS_FWSUP_TIMEOUT 7 +#define BRCMF_E_STATUS_FWSUP_WAIT_M3 8 +#define BRCMF_E_STATUS_FWSUP_PREP_M4 9 +#define BRCMF_E_STATUS_FWSUP_WAIT_G1 10 +#define BRCMF_E_STATUS_FWSUP_PREP_G2 11 + /* reason field values in struct brcmf_event_msg */ #define BRCMF_E_REASON_INITIAL_ASSOC 0 #define BRCMF_E_REASON_LOW_RSSI 1 @@ -161,6 +171,26 @@ enum brcmf_fweh_event_code { #define BRCMF_E_REASON_TDLS_PEER_CONNECTED 1 #define BRCMF_E_REASON_TDLS_PEER_DISCONNECTED 2 +/* reason field values for PSK_SUP event */ +#define BRCMF_E_REASON_FWSUP_OTHER 0 +#define BRCMF_E_REASON_FWSUP_DECRYPT_KEY_DATA 1 +#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP128 2 +#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP40 3 +#define BRCMF_E_REASON_FWSUP_UNSUP_KEY_LEN 4 +#define BRCMF_E_REASON_FWSUP_PW_KEY_CIPHER 5 +#define BRCMF_E_REASON_FWSUP_MSG3_TOO_MANY_IE 6 +#define BRCMF_E_REASON_FWSUP_MSG3_IE_MISMATCH 7 +#define BRCMF_E_REASON_FWSUP_NO_INSTALL_FLAG 8 +#define BRCMF_E_REASON_FWSUP_MSG3_NO_GTK 9 +#define BRCMF_E_REASON_FWSUP_GRP_KEY_CIPHER 10 +#define BRCMF_E_REASON_FWSUP_GRP_MSG1_NO_GTK 11 +#define BRCMF_E_REASON_FWSUP_GTK_DECRYPT_FAIL 12 +#define BRCMF_E_REASON_FWSUP_SEND_FAIL 13 +#define BRCMF_E_REASON_FWSUP_DEAUTH 14 +#define BRCMF_E_REASON_FWSUP_WPA_PSK_TMO 15 +#define BRCMF_E_REASON_FWSUP_WPA_PSK_M1_TMO 16 +#define BRCMF_E_REASON_FWSUP_WPA_PSK_M3_TMO 17 + /* action field values for brcmf_ifevent */ #define BRCMF_E_IF_ADD 1 #define BRCMF_E_IF_DEL 2 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h index 3a9a76dd9222..63b1287e2e6d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h @@ -85,6 +85,7 @@ #define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 #define BRCMF_C_GET_VAR 262 #define BRCMF_C_SET_VAR 263 +#define BRCMF_C_SET_WSEC_PMK 268 s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 9a1eb5ab6c4b..8391989b1882 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -45,6 +45,9 @@ #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff #define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 +#define BRCMF_WSEC_MAX_PSK_LEN 32 +#define BRCMF_WSEC_PASSPHRASE BIT(0) + /* primary (ie tx) key */ #define BRCMF_PRIMARY_KEY (1 << 1) #define DOT11_BSSTYPE_ANY 2 @@ -470,6 +473,19 @@ struct brcmf_wsec_key_le { u8 ea[ETH_ALEN]; /* per station */ }; +/** + * struct brcmf_wsec_pmk_le - firmware pmk material. + * + * @key_len: number of octets in key material. + * @flags: key handling qualifiers. + * @key: PMK key material. + */ +struct brcmf_wsec_pmk_le { + __le16 key_len; + __le16 flags; + u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; +}; + /* Used to get specific STA parameters */ struct brcmf_scb_val_le { __le32 val; @@ -806,6 +822,17 @@ struct brcmf_pno_macaddr_le { }; /** + * struct brcmf_pno_bssid_le - bssid configuration for PNO scan. + * + * @bssid: BSS network identifier. + * @flags: flags for this BSSID. + */ +struct brcmf_pno_bssid_le { + u8 bssid[ETH_ALEN]; + __le16 flags; +}; + +/** * struct brcmf_pktcnt_le - packet counters. * * @rx_good_pkt: packets (MSDUs & MMPDUs) received from this station @@ -835,4 +862,69 @@ struct brcmf_gtk_keyinfo_le { u8 replay_counter[BRCMF_RSN_REPLAY_LEN]; }; +#define BRCMF_PNO_REPORT_NO_BATCH BIT(2) + +/** + * struct brcmf_gscan_bucket_config - configuration data for channel bucket. + * + * @bucket_end_index: last channel index in @channel_list in + * @struct brcmf_pno_config_le. + * @bucket_freq_multiple: scan interval expressed in N * @scan_freq. + * @flag: channel bucket report flags. + * @reserved: for future use. + * @repeat: number of scan at interval for exponential scan. + * @max_freq_multiple: maximum scan interval for exponential scan. + */ +struct brcmf_gscan_bucket_config { + u8 bucket_end_index; + u8 bucket_freq_multiple; + u8 flag; + u8 reserved; + __le16 repeat; + __le16 max_freq_multiple; +}; + +/* version supported which must match firmware */ +#define BRCMF_GSCAN_CFG_VERSION 2 + +/** + * enum brcmf_gscan_cfg_flags - bit values for gscan flags. + * + * @BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS: send probe responses/beacons to host. + * @BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN: all buckets will be included in + * first scan cycle. + * @BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY: indicated only flags member is changed. + */ +enum brcmf_gscan_cfg_flags { + BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS = BIT(0), + BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN = BIT(3), + BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY = BIT(7), +}; + +/** + * struct brcmf_gscan_config - configuration data for gscan. + * + * @version: version of the api to match firmware. + * @flags: flags according %enum brcmf_gscan_cfg_flags. + * @buffer_threshold: percentage threshold of buffer to generate an event. + * @swc_nbssid_threshold: number of BSSIDs with significant change that + * will generate an event. + * @swc_rssi_window_size: size of rssi cache buffer (max=8). + * @count_of_channel_buckets: number of array members in @bucket. + * @retry_threshold: !unknown! + * @lost_ap_window: !unknown! + * @bucket: array of channel buckets. + */ +struct brcmf_gscan_config { + __le16 version; + u8 flags; + u8 buffer_threshold; + u8 swc_nbssid_threshold; + u8 swc_rssi_window_size; + u8 count_of_channel_buckets; + u8 retry_threshold; + __le16 lost_ap_window; + struct brcmf_gscan_bucket_config bucket[1]; +}; + #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index aa299c47bfa2..2ce675ab40ef 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2208,6 +2208,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, err = brcmf_net_attach(ifp, true); if (err) { brcmf_err("Registering netdevice failed\n"); + free_netdev(ifp->ndev); goto fail; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index 6c3bde83d070..ffa243e2e2d0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/netdevice.h> +#include <linux/gcd.h> #include <net/cfg80211.h> #include "core.h" @@ -35,6 +36,67 @@ #define BRCMF_PNO_HIDDEN_BIT 2 #define BRCMF_PNO_SCHED_SCAN_PERIOD 30 +#define BRCMF_PNO_MAX_BUCKETS 16 +#define GSCAN_BATCH_NO_THR_SET 101 +#define GSCAN_RETRY_THRESHOLD 3 + +struct brcmf_pno_info { + int n_reqs; + struct cfg80211_sched_scan_request *reqs[BRCMF_PNO_MAX_BUCKETS]; + struct mutex req_lock; +}; + +#define ifp_to_pno(_ifp) ((_ifp)->drvr->config->pno) + +static int brcmf_pno_store_request(struct brcmf_pno_info *pi, + struct cfg80211_sched_scan_request *req) +{ + if (WARN(pi->n_reqs == BRCMF_PNO_MAX_BUCKETS, + "pno request storage full\n")) + return -ENOSPC; + + brcmf_dbg(SCAN, "reqid=%llu\n", req->reqid); + mutex_lock(&pi->req_lock); + pi->reqs[pi->n_reqs++] = req; + mutex_unlock(&pi->req_lock); + return 0; +} + +static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) +{ + int i, err = 0; + + mutex_lock(&pi->req_lock); + + /* find request */ + for (i = 0; i < pi->n_reqs; i++) { + if (pi->reqs[i]->reqid == reqid) + break; + } + /* request not found */ + if (WARN(i == pi->n_reqs, "reqid not found\n")) { + err = -ENOENT; + goto done; + } + + brcmf_dbg(SCAN, "reqid=%llu\n", reqid); + pi->n_reqs--; + + /* if last we are done */ + if (!pi->n_reqs || i == pi->n_reqs) + goto done; + + /* fill the gap with remaining requests */ + while (i <= pi->n_reqs - 1) { + pi->reqs[i] = pi->reqs[i + 1]; + i++; + } + +done: + mutex_unlock(&pi->req_lock); + return err; +} + static int brcmf_pno_channel_config(struct brcmf_if *ifp, struct brcmf_pno_config_le *cfg) { @@ -57,16 +119,11 @@ static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq, /* set extra pno params */ flags = BIT(BRCMF_PNO_IMMEDIATE_SCAN_BIT) | - BIT(BRCMF_PNO_REPORT_SEPARATELY_BIT) | BIT(BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); pfn_param.repeat = BRCMF_PNO_REPEAT; pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; /* set up pno scan fr */ - if (scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) { - brcmf_dbg(SCAN, "scan period too small, using minimum\n"); - scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD; - } pfn_param.scan_freq = cpu_to_le32(scan_freq); if (mscan) { @@ -101,12 +158,24 @@ exit: return err; } -static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr, - u8 *mac_mask) +static int brcmf_pno_set_random(struct brcmf_if *ifp, struct brcmf_pno_info *pi) { struct brcmf_pno_macaddr_le pfn_mac; + u8 *mac_addr = NULL; + u8 *mac_mask = NULL; int err, i; + for (i = 0; i < pi->n_reqs; i++) + if (pi->reqs[i]->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + mac_addr = pi->reqs[i]->mac_addr; + mac_mask = pi->reqs[i]->mac_addr_mask; + break; + } + + /* no random mac requested */ + if (!mac_addr) + return 0; + pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC; @@ -120,6 +189,8 @@ static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr, /* Set locally administered */ pfn_mac.mac[0] |= 0x02; + brcmf_dbg(SCAN, "enabling random mac: reqid=%llu mac=%pM\n", + pi->reqs[i]->reqid, pfn_mac.mac); err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac, sizeof(pfn_mac)); if (err) @@ -132,6 +203,7 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid, bool active) { struct brcmf_pno_net_param_le pfn; + int err; pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); @@ -142,7 +214,28 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid, pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len); memcpy(pfn.ssid.SSID, ssid->ssid, ssid->ssid_len); - return brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn)); + + brcmf_dbg(SCAN, "adding ssid=%.32s (active=%d)\n", ssid->ssid, active); + err = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn)); + if (err < 0) + brcmf_err("adding failed: err=%d\n", err); + return err; +} + +static int brcmf_pno_add_bssid(struct brcmf_if *ifp, const u8 *bssid) +{ + struct brcmf_pno_bssid_le bssid_cfg; + int err; + + memcpy(bssid_cfg.bssid, bssid, ETH_ALEN); + bssid_cfg.flags = 0; + + brcmf_dbg(SCAN, "adding bssid=%pM\n", bssid); + err = brcmf_fil_iovar_data_set(ifp, "pfn_add_bssid", &bssid_cfg, + sizeof(bssid_cfg)); + if (err < 0) + brcmf_err("adding failed: err=%d\n", err); + return err; } static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid, @@ -163,7 +256,7 @@ static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid, return false; } -int brcmf_pno_clean(struct brcmf_if *ifp) +static int brcmf_pno_clean(struct brcmf_if *ifp) { int ret; @@ -179,63 +272,320 @@ int brcmf_pno_clean(struct brcmf_if *ifp) return ret; } -int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, - struct cfg80211_sched_scan_request *req) +static int brcmf_pno_get_bucket_channels(struct cfg80211_sched_scan_request *r, + struct brcmf_pno_config_le *pno_cfg) { - struct brcmf_pno_config_le pno_cfg; - struct cfg80211_ssid *ssid; + u32 n_chan = le32_to_cpu(pno_cfg->channel_num); u16 chan; - int i, ret; + int i, err = 0; - /* clean up everything */ - ret = brcmf_pno_clean(ifp); - if (ret < 0) { - brcmf_err("failed error=%d\n", ret); - return ret; + for (i = 0; i < r->n_channels; i++) { + if (n_chan >= BRCMF_NUMCHANNELS) { + err = -ENOSPC; + goto done; + } + chan = r->channels[i]->hw_value; + brcmf_dbg(SCAN, "[%d] Chan : %u\n", n_chan, chan); + pno_cfg->channel_list[n_chan++] = cpu_to_le16(chan); } + /* return number of channels */ + err = n_chan; +done: + pno_cfg->channel_num = cpu_to_le32(n_chan); + return err; +} - /* configure pno */ - ret = brcmf_pno_config(ifp, req->scan_plans[0].interval, 0, 0); - if (ret < 0) - return ret; - - /* configure random mac */ - if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { - ret = brcmf_pno_set_random(ifp, req->mac_addr, - req->mac_addr_mask); - if (ret < 0) - return ret; +static int brcmf_pno_prep_fwconfig(struct brcmf_pno_info *pi, + struct brcmf_pno_config_le *pno_cfg, + struct brcmf_gscan_bucket_config **buckets, + u32 *scan_freq) +{ + struct cfg80211_sched_scan_request *sr; + struct brcmf_gscan_bucket_config *fw_buckets; + int i, err, chidx; + + brcmf_dbg(SCAN, "n_reqs=%d\n", pi->n_reqs); + if (WARN_ON(!pi->n_reqs)) + return -ENODATA; + + /* + * actual scan period is determined using gcd() for each + * scheduled scan period. + */ + *scan_freq = pi->reqs[0]->scan_plans[0].interval; + for (i = 1; i < pi->n_reqs; i++) { + sr = pi->reqs[i]; + *scan_freq = gcd(sr->scan_plans[0].interval, *scan_freq); + } + if (*scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) { + brcmf_dbg(SCAN, "scan period too small, using minimum\n"); + *scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD; } - /* configure channels to use */ - for (i = 0; i < req->n_channels; i++) { - chan = req->channels[i]->hw_value; - pno_cfg.channel_list[i] = cpu_to_le16(chan); + *buckets = NULL; + fw_buckets = kcalloc(pi->n_reqs, sizeof(*fw_buckets), GFP_KERNEL); + if (!fw_buckets) + return -ENOMEM; + + memset(pno_cfg, 0, sizeof(*pno_cfg)); + for (i = 0; i < pi->n_reqs; i++) { + sr = pi->reqs[i]; + chidx = brcmf_pno_get_bucket_channels(sr, pno_cfg); + if (chidx < 0) { + err = chidx; + goto fail; + } + fw_buckets[i].bucket_end_index = chidx - 1; + fw_buckets[i].bucket_freq_multiple = + sr->scan_plans[0].interval / *scan_freq; + /* assure period is non-zero */ + if (!fw_buckets[i].bucket_freq_multiple) + fw_buckets[i].bucket_freq_multiple = 1; + fw_buckets[i].flag = BRCMF_PNO_REPORT_NO_BATCH; } - if (req->n_channels) { - pno_cfg.channel_num = cpu_to_le32(req->n_channels); - brcmf_pno_channel_config(ifp, &pno_cfg); + + if (BRCMF_SCAN_ON()) { + brcmf_err("base period=%u\n", *scan_freq); + for (i = 0; i < pi->n_reqs; i++) { + brcmf_err("[%d] period %u max %u repeat %u flag %x idx %u\n", + i, fw_buckets[i].bucket_freq_multiple, + le16_to_cpu(fw_buckets[i].max_freq_multiple), + fw_buckets[i].repeat, fw_buckets[i].flag, + fw_buckets[i].bucket_end_index); + } } + *buckets = fw_buckets; + return pi->n_reqs; - /* configure each match set */ - for (i = 0; i < req->n_match_sets; i++) { - ssid = &req->match_sets[i].ssid; - if (!ssid->ssid_len) { - brcmf_err("skip broadcast ssid\n"); - continue; +fail: + kfree(fw_buckets); + return err; +} + +static int brcmf_pno_config_networks(struct brcmf_if *ifp, + struct brcmf_pno_info *pi) +{ + struct cfg80211_sched_scan_request *r; + struct cfg80211_match_set *ms; + bool active; + int i, j, err = 0; + + for (i = 0; i < pi->n_reqs; i++) { + r = pi->reqs[i]; + + for (j = 0; j < r->n_match_sets; j++) { + ms = &r->match_sets[j]; + if (ms->ssid.ssid_len) { + active = brcmf_is_ssid_active(&ms->ssid, r); + err = brcmf_pno_add_ssid(ifp, &ms->ssid, + active); + } + if (!err && is_valid_ether_addr(ms->bssid)) + err = brcmf_pno_add_bssid(ifp, ms->bssid); + + if (err < 0) + return err; } + } + return 0; +} + +static int brcmf_pno_config_sched_scans(struct brcmf_if *ifp) +{ + struct brcmf_pno_info *pi; + struct brcmf_gscan_config *gscan_cfg; + struct brcmf_gscan_bucket_config *buckets; + struct brcmf_pno_config_le pno_cfg; + size_t gsz; + u32 scan_freq; + int err, n_buckets; + + pi = ifp_to_pno(ifp); + n_buckets = brcmf_pno_prep_fwconfig(pi, &pno_cfg, &buckets, + &scan_freq); + if (n_buckets < 0) + return n_buckets; + + gsz = sizeof(*gscan_cfg) + (n_buckets - 1) * sizeof(*buckets); + gscan_cfg = kzalloc(gsz, GFP_KERNEL); + if (!gscan_cfg) { + err = -ENOMEM; + goto free_buckets; + } - ret = brcmf_pno_add_ssid(ifp, ssid, - brcmf_is_ssid_active(ssid, req)); - if (ret < 0) - brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n", - ret == 0 ? "set" : "failed", ssid->ssid); + /* clean up everything */ + err = brcmf_pno_clean(ifp); + if (err < 0) { + brcmf_err("failed error=%d\n", err); + goto free_gscan; } + + /* configure pno */ + err = brcmf_pno_config(ifp, scan_freq, 0, 0); + if (err < 0) + goto free_gscan; + + err = brcmf_pno_channel_config(ifp, &pno_cfg); + if (err < 0) + goto clean; + + gscan_cfg->version = cpu_to_le16(BRCMF_GSCAN_CFG_VERSION); + gscan_cfg->retry_threshold = GSCAN_RETRY_THRESHOLD; + gscan_cfg->buffer_threshold = GSCAN_BATCH_NO_THR_SET; + gscan_cfg->flags = BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN; + + gscan_cfg->count_of_channel_buckets = n_buckets; + memcpy(&gscan_cfg->bucket[0], buckets, + n_buckets * sizeof(*buckets)); + + err = brcmf_fil_iovar_data_set(ifp, "pfn_gscan_cfg", gscan_cfg, gsz); + + if (err < 0) + goto clean; + + /* configure random mac */ + err = brcmf_pno_set_random(ifp, pi); + if (err < 0) + goto clean; + + err = brcmf_pno_config_networks(ifp, pi); + if (err < 0) + goto clean; + /* Enable the PNO */ - ret = brcmf_fil_iovar_int_set(ifp, "pfn", 1); + err = brcmf_fil_iovar_int_set(ifp, "pfn", 1); + +clean: + if (err < 0) + brcmf_pno_clean(ifp); +free_gscan: + kfree(gscan_cfg); +free_buckets: + kfree(buckets); + return err; +} + +int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, + struct cfg80211_sched_scan_request *req) +{ + struct brcmf_pno_info *pi; + int ret; + + brcmf_dbg(TRACE, "reqid=%llu\n", req->reqid); + + pi = ifp_to_pno(ifp); + ret = brcmf_pno_store_request(pi, req); if (ret < 0) - brcmf_err("PNO enable failed!! ret=%d\n", ret); + return ret; - return ret; + ret = brcmf_pno_config_sched_scans(ifp); + if (ret < 0) { + brcmf_pno_remove_request(pi, req->reqid); + if (pi->n_reqs) + (void)brcmf_pno_config_sched_scans(ifp); + return ret; + } + return 0; } +int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid) +{ + struct brcmf_pno_info *pi; + int err; + + brcmf_dbg(TRACE, "reqid=%llu\n", reqid); + + pi = ifp_to_pno(ifp); + err = brcmf_pno_remove_request(pi, reqid); + if (err) + return err; + + brcmf_pno_clean(ifp); + + if (pi->n_reqs) + (void)brcmf_pno_config_sched_scans(ifp); + + return 0; +} + +int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_pno_info *pi; + + brcmf_dbg(TRACE, "enter\n"); + pi = kzalloc(sizeof(*pi), GFP_KERNEL); + if (!pi) + return -ENOMEM; + + cfg->pno = pi; + mutex_init(&pi->req_lock); + return 0; +} + +void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_pno_info *pi; + + brcmf_dbg(TRACE, "enter\n"); + pi = cfg->pno; + cfg->pno = NULL; + + WARN_ON(pi->n_reqs); + mutex_destroy(&pi->req_lock); + kfree(pi); +} + +void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan) +{ + /* scheduled scan settings */ + wiphy->max_sched_scan_reqs = gscan ? BRCMF_PNO_MAX_BUCKETS : 1; + wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; +} + +u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket) +{ + u64 reqid = 0; + + mutex_lock(&pi->req_lock); + + if (bucket < pi->n_reqs) + reqid = pi->reqs[bucket]->reqid; + + mutex_unlock(&pi->req_lock); + return reqid; +} + +u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, + struct brcmf_pno_net_info_le *ni) +{ + struct cfg80211_sched_scan_request *req; + struct cfg80211_match_set *ms; + u32 bucket_map = 0; + int i, j; + + mutex_lock(&pi->req_lock); + for (i = 0; i < pi->n_reqs; i++) { + req = pi->reqs[i]; + + if (!req->n_match_sets) + continue; + for (j = 0; j < req->n_match_sets; j++) { + ms = &req->match_sets[j]; + if (ms->ssid.ssid_len == ni->SSID_len && + !memcmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) { + bucket_map |= BIT(i); + break; + } + if (is_valid_ether_addr(ms->bssid) && + !memcmp(ms->bssid, ni->bssid, ETH_ALEN)) { + bucket_map |= BIT(i); + break; + } + } + } + mutex_unlock(&pi->req_lock); + return bucket_map; +} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h index bae55b2af78c..cd9e35ae3b21 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h @@ -21,12 +21,8 @@ #define BRCMF_PNO_SCHED_SCAN_MIN_PERIOD 10 #define BRCMF_PNO_SCHED_SCAN_MAX_PERIOD 508 -/** - * brcmf_pno_clean - disable and clear pno in firmware. - * - * @ifp: interface object used. - */ -int brcmf_pno_clean(struct brcmf_if *ifp); +/* forward declaration */ +struct brcmf_pno_info; /** * brcmf_pno_start_sched_scan - initiate scheduled scan on device. @@ -37,4 +33,51 @@ int brcmf_pno_clean(struct brcmf_if *ifp); int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, struct cfg80211_sched_scan_request *req); +/** + * brcmf_pno_stop_sched_scan - terminate scheduled scan on device. + * + * @ifp: interface object used. + * @reqid: unique identifier of scan to be stopped. + */ +int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid); + +/** + * brcmf_pno_wiphy_params - fill scheduled scan parameters in wiphy instance. + * + * @wiphy: wiphy instance to be used. + * @gscan: indicates whether the device has support for g-scan feature. + */ +void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan); + +/** + * brcmf_pno_attach - allocate and attach module information. + * + * @cfg: cfg80211 context used. + */ +int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg); + +/** + * brcmf_pno_detach - detach and free module information. + * + * @cfg: cfg80211 context used. + */ +void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg); + +/** + * brcmf_pno_find_reqid_by_bucket - find request id for given bucket index. + * + * @pi: pno instance used. + * @bucket: index of firmware bucket. + */ +u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket); + +/** + * brcmf_pno_get_bucket_map - determine bucket map for given netinfo. + * + * @pi: pno instance used. + * @netinfo: netinfo to compare with bucket configuration. + */ +u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, + struct brcmf_pno_net_info_le *netinfo); + #endif /* _BRCMF_PNO_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 5653d6dd38f6..fbcbb4325936 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -612,7 +612,9 @@ BRCMF_FW_NVRAM_DEF(43340, "brcmfmac43340-sdio.bin", "brcmfmac43340-sdio.txt"); BRCMF_FW_NVRAM_DEF(4335, "brcmfmac4335-sdio.bin", "brcmfmac4335-sdio.txt"); BRCMF_FW_NVRAM_DEF(43362, "brcmfmac43362-sdio.bin", "brcmfmac43362-sdio.txt"); BRCMF_FW_NVRAM_DEF(4339, "brcmfmac4339-sdio.bin", "brcmfmac4339-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43430, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt"); +BRCMF_FW_NVRAM_DEF(43430A0, "brcmfmac43430a0-sdio.bin", "brcmfmac43430a0-sdio.txt"); +/* Note the names are not postfixed with a1 for backward compatibility */ +BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt"); BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt"); BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt"); BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt"); @@ -630,7 +632,8 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFF, 43430), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356) @@ -2034,6 +2037,7 @@ brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus) static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) { + struct brcmf_bus_stats *stats; u16 head_pad; u8 *dat_buf; @@ -2043,16 +2047,18 @@ static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) head_pad = ((unsigned long)dat_buf % bus->head_align); if (head_pad) { if (skb_headroom(pkt) < head_pad) { - bus->sdiodev->bus_if->tx_realloc++; - head_pad = 0; - if (skb_cow(pkt, head_pad)) + stats = &bus->sdiodev->bus_if->stats; + atomic_inc(&stats->pktcowed); + if (skb_cow_head(pkt, head_pad)) { + atomic_inc(&stats->pktcow_failed); return -ENOMEM; + } } skb_push(pkt, head_pad); dat_buf = (u8 *)(pkt->data); - memset(dat_buf, 0, head_pad + bus->tx_hdrlen); } - return head_pad; + memset(dat_buf, 0, head_pad + bus->tx_hdrlen); + return 0; } /** diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index 6a13303af2b7..84143a02adce 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -3330,7 +3330,7 @@ static void airo_handle_rx(struct airo_info *ai) } skb_reserve(skb, 2); /* This way the IP header is aligned */ - buffer = (__le16 *) skb_put(skb, len + hdrlen); + buffer = skb_put(skb, len + hdrlen); if (test_bit(FLAG_802_11, &ai->flags)) { buffer[0] = fc; bap_read(ai, buffer + 1, hdrlen - 2, BAP0); @@ -3734,7 +3734,7 @@ static void mpi_receive_802_11(struct airo_info *ai) ai->dev->stats.rx_dropped++; goto badrx; } - buffer = (u16*)skb_put (skb, len + hdrlen); + buffer = skb_put(skb, len + hdrlen); memcpy ((char *)buffer, ptr, hdrlen); ptr += hdrlen; if (hdrlen == 24) diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 5b79e2ec3a16..9368abdf18e2 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -10272,8 +10272,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, printk(KERN_INFO "Adding frag %d %d...\n", j, size); - memcpy(skb_put(skb, size), - txb->fragments[j]->data + hdr_len, size); + skb_put_data(skb, + txb->fragments[j]->data + hdr_len, + size); } dev_kfree_skb_any(txb->fragments[i]); txb->fragments[i] = skb; @@ -10368,7 +10369,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, if (!dst) continue; - rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); + rt_hdr = skb_put(dst, sizeof(*rt_hdr)); rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION; rt_hdr->it_pad = 0; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index 048f1e3ada11..84205aa508df 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -359,7 +359,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) goto failed; skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); - memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); + skb_put_data(skb_new, &header, hdr_len); snapped = 1; libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), ether_type); @@ -439,8 +439,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) if (rts_required) { skb_frag = txb->fragments[0]; - frag_hdr = - (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + frag_hdr = skb_put(skb_frag, hdr_len); /* * Set header frame_ctl to the RTS. @@ -470,9 +469,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) skb_reserve(skb_frag, crypt->ops->extra_mpdu_prefix_len); - frag_hdr = - (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); - memcpy(frag_hdr, &header, hdr_len); + frag_hdr = skb_put_data(skb_frag, &header, hdr_len); /* If this is not the last fragment, then add the MOREFRAGS * bit to the frame control */ diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 080ea8155b90..dbf164d48ed3 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -520,7 +520,7 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, * and do not consume a full page */ if (len <= SMALL_PACKET_SIZE) { - memcpy(skb_put(skb, len), rx_hdr->payload, len); + skb_put_data(skb, rx_hdr->payload, len); } else { skb_add_rx_frag(skb, 0, rxb->page, (void *)rx_hdr->payload - (void *)pkt, len, diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 49a2ff15ddae..5b51fba75595 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -606,7 +606,7 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr, } if (len <= SMALL_PACKET_SIZE) { - memcpy(skb_put(skb, len), hdr, len); + skb_put_data(skb, hdr, len); } else { skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len, PAGE_SIZE << il->hw_params.rx_page_order); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 140b6ea8f7cc..8d5acda92a9b 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5147,6 +5147,8 @@ set_ch_out: if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) { il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS); + if (!il->power_data.ps_disabled) + IL_WARN_ONCE("Enabling power save might cause firmware crashes\n"); ret = il_power_update_mode(il, false); if (ret) D_MAC80211("Error setting sleep level\n"); diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index 3bba521d2cd9..18c60c92e3a3 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -45,6 +45,7 @@ struct il_tx_queue; #define IL_ERR(f, a...) dev_err(&il->pci_dev->dev, f, ## a) #define IL_WARN(f, a...) dev_warn(&il->pci_dev->dev, f, ## a) +#define IL_WARN_ONCE(f, a...) dev_warn_once(&il->pci_dev->dev, f, ## a) #define IL_INFO(f, a...) dev_info(&il->pci_dev->dev, f, ## a) #define RX_QUEUE_SIZE 256 diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 411cb91c102f..20bd261223af 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -3,14 +3,14 @@ obj-$(CONFIG_IWLWIFI) += iwlwifi.o iwlwifi-objs += iwl-io.o iwlwifi-objs += iwl-drv.o iwlwifi-objs += iwl-debug.o -iwlwifi-objs += iwl-notif-wait.o iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o pcie/tx-gen2.o -iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o -iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o +iwlwifi-$(CONFIG_IWLDVM) += cfg/1000.o cfg/2000.o cfg/5000.o cfg/6000.o +iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/a000.o iwlwifi-objs += iwl-trans.o +iwlwifi-objs += fw/notif-wait.o iwlwifi-objs += $(iwlwifi-m) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-1000.c b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c index b2573b1d1506..b2573b1d1506 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-2000.c b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c index 1b32ad413b9e..1b32ad413b9e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-5000.c b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c index 4aa8f0a05c8a..4aa8f0a05c8a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c index 39335b7b0c16..39335b7b0c16 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c index 45e2efc70d19..45e2efc70d19 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index 89137717c1fc..5081720608af 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -70,8 +70,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 30 -#define IWL8265_UCODE_API_MAX 30 +#define IWL8000_UCODE_API_MAX 33 +#define IWL8265_UCODE_API_MAX 33 /* Lowest firmware API version supported */ #define IWL8000_UCODE_API_MIN 22 @@ -98,7 +98,6 @@ IWL8265_FW_PRE __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_8000 10 -#define DEFAULT_NVM_FILE_FAMILY_8000B "nvmData-8000B" #define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" /* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */ @@ -162,10 +161,11 @@ static const struct iwl_tt_params iwl8000_tt_params = { .dccm2_len = IWL8260_DCCM2_LEN, \ .smem_offset = IWL8260_SMEM_OFFSET, \ .smem_len = IWL8260_SMEM_LEN, \ - .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, \ .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \ .thermal_params = &iwl8000_tt_params, \ - .apmg_not_supported = true + .apmg_not_supported = true, \ + .ext_nvm = true, \ + .dbgc_supported = true #define IWL_DEVICE_8000 \ IWL_DEVICE_8000_COMMON, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 110ceefccc15..b4ecd1fe1374 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 30 +#define IWL9000_UCODE_API_MAX 33 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 30 @@ -73,10 +73,13 @@ #define IWL9000_SMEM_LEN 0x68000 #define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" +#define IWL9000RFB_FW_PRE "iwlwifi-9000-pu-a0-jf-b0-" #define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" #define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" #define IWL9000_MODULE_FIRMWARE(api) \ IWL9000_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9000RFB_MODULE_FIRMWARE(api) \ + IWL9000RFB_FW_PRE "-" __stringify(api) ".ucode" #define IWL9260A_MODULE_FIRMWARE(api) \ IWL9260A_FW_PRE "-" __stringify(api) ".ucode" #define IWL9260B_MODULE_FIRMWARE(api) \ @@ -125,7 +128,7 @@ static const struct iwl_tt_params iwl9000_tt_params = { #define IWL_DEVICE_9000 \ .ucode_api_max = IWL9000_UCODE_API_MAX, \ .ucode_api_min = IWL9000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_8000, \ + .device_family = IWL_DEVICE_FAMILY_9000, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl9000_base_params, \ @@ -144,7 +147,9 @@ static const struct iwl_tt_params iwl9000_tt_params = { .mq_rx_supported = true, \ .vht_mu_mimo_supported = true, \ .mac_addr_from_csr = true, \ - .rf_id = true + .rf_id = true, \ + .ext_nvm = true, \ + .dbgc_supported = true const struct iwl_cfg iwl9160_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9160", @@ -182,6 +187,7 @@ const struct iwl_cfg iwl9270_2ac_cfg = { const struct iwl_cfg iwl9460_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9460", .fw_name_pre = IWL9000_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, IWL_DEVICE_9000, .ht_params = &iwl9000_ht_params, .nvm_ver = IWL9000_NVM_VERSION, @@ -193,6 +199,7 @@ const struct iwl_cfg iwl9460_2ac_cfg = { const struct iwl_cfg iwl9560_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9560", .fw_name_pre = IWL9000_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, IWL_DEVICE_9000, .ht_params = &iwl9000_ht_params, .nvm_ver = IWL9000_NVM_VERSION, @@ -202,5 +209,6 @@ const struct iwl_cfg iwl9560_2ac_cfg = { }; MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c index c648cfb981a3..98f24cd1b44f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL_A000_UCODE_API_MAX 30 +#define IWL_A000_UCODE_API_MAX 33 /* Lowest firmware API version supported */ #define IWL_A000_UCODE_API_MIN 24 @@ -74,7 +74,7 @@ #define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" #define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" -#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-a0-hrcdb-a0-" +#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" #define IWL_A000_HR_MODULE_FIRMWARE(api) \ IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode" @@ -103,7 +103,7 @@ static const struct iwl_ht_params iwl_a000_ht_params = { #define IWL_DEVICE_A000 \ .ucode_api_max = IWL_A000_UCODE_API_MAX, \ .ucode_api_min = IWL_A000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_8000, \ + .device_family = IWL_DEVICE_FAMILY_A000, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl_a000_base_params, \ @@ -123,7 +123,9 @@ static const struct iwl_ht_params iwl_a000_ht_params = { .mac_addr_from_csr = true, \ .use_tfh = true, \ .rf_id = true, \ - .gen2 = true + .gen2 = true, \ + .ext_nvm = true, \ + .dbgc_supported = true const struct iwl_cfg iwla000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC a000", @@ -156,5 +158,15 @@ const struct iwl_cfg iwla000_2ac_cfg_jf = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwla000_2ax_cfg_hr = { + .name = "Intel(R) Dual Band Wireless AX a000", + .fw_name_pre = IWL_A000_HR_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + MODULE_FIRMWARE(IWL_A000_HR_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_A000_JF_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index 376c79337a0e..482ac8fdc67b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -681,11 +681,10 @@ DEBUGFS_READ_FILE_OPS(temperature); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); DEBUGFS_READ_FILE_OPS(current_sleep_command); -static const char *fmt_value = " %-30s %10u\n"; -static const char *fmt_hex = " %-30s 0x%02X\n"; -static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; -static const char *fmt_header = - "%-32s current cumulative delta max\n"; +#define fmt_value " %-30s %10u\n" +#define fmt_hex " %-30s 0x%02X\n" +#define fmt_table " %-30s %10u %10u %10u %10u\n" +#define fmt_header "%-32s current cumulative delta max\n" static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) { @@ -2309,10 +2308,10 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - bool restart_fw = iwlwifi_mod_params.restart_fw; + bool fw_restart = iwlwifi_mod_params.fw_restart; int __maybe_unused ret; - iwlwifi_mod_params.restart_fw = true; + iwlwifi_mod_params.fw_restart = true; mutex_lock(&priv->mutex); @@ -2321,7 +2320,7 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, mutex_unlock(&priv->mutex); - iwlwifi_mod_params.restart_fw = restart_fw; + iwlwifi_mod_params.fw_restart = fw_restart; return count; } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h index 8148df61a916..cceb4cd8e501 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h @@ -38,13 +38,13 @@ #include <linux/slab.h> #include <linux/mutex.h> -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-eeprom-parse.h" #include "iwl-csr.h" #include "iwl-debug.h" #include "iwl-agn-hw.h" #include "iwl-op-mode.h" -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-trans.h" #include "led.h" diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 74e52f7c5aa1..2b6ffbc46fa5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -1157,7 +1157,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) if (ret) goto out; - if (!iwlwifi_mod_params.sw_crypto) { + if (!iwlwifi_mod_params.swcrypto) { /* mark all keys clear */ priv->ucode_key_table = 0; ctx->key_mapping_keys = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 444c74371929..82caae02dd09 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -138,7 +138,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, * packets, so enabling it with software crypto isn't safe) */ if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && - !iwlwifi_mod_params.sw_crypto) + !iwlwifi_mod_params.swcrypto) ieee80211_hw_set(hw, MFP_CAPABLE); hw->sta_data_size = sizeof(struct iwl_station_priv); @@ -171,7 +171,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | WIPHY_WOWLAN_RFKILL_RELEASE; - if (!iwlwifi_mod_params.sw_crypto) + if (!iwlwifi_mod_params.swcrypto) priv->wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE; @@ -348,7 +348,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - if (iwlwifi_mod_params.sw_crypto) + if (iwlwifi_mod_params.swcrypto) return; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -624,7 +624,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (iwlwifi_mod_params.sw_crypto) { + if (iwlwifi_mod_params.swcrypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index b49848683587..2acd94da9efe 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1371,7 +1371,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, /* is antenna coupling more than 35dB ? */ priv->bt_ant_couple_ok = - (iwlwifi_mod_params.ant_coupling > + (iwlwifi_mod_params.antenna_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ? true : false; @@ -1513,7 +1513,7 @@ out_destroy_workqueue: out_free_eeprom_blob: kfree(priv->eeprom_blob); out_free_eeprom: - iwl_free_nvm_data(priv->nvm_data); + kfree(priv->nvm_data); out_free_hw: ieee80211_free_hw(priv->hw); out: @@ -1532,7 +1532,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) iwl_tt_exit(priv); kfree(priv->eeprom_blob); - iwl_free_nvm_data(priv->nvm_data); + kfree(priv->nvm_data); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); @@ -1958,7 +1958,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) } if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - if (iwlwifi_mod_params.restart_fw) { + if (iwlwifi_mod_params.fw_restart) { IWL_DEBUG_FW_ERRORS(priv, "Restarting adapter due to uCode error.\n"); queue_work(priv->workqueue, &priv->restart); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index adfd6307edca..c942830af2b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -639,7 +639,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, } /* In case of HW accelerated crypto and bad decryption, drop */ - if (!iwlwifi_mod_params.sw_crypto && + if (!iwlwifi_mod_params.swcrypto && iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; @@ -657,7 +657,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, */ hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); - memcpy(skb_put(skb, hdrlen), hdr, hdrlen); + skb_put_data(skb, hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 087e579854ab..8f3e5586eda9 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -1120,7 +1120,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } - iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.swcrypto); IWL_DEBUG_INFO(priv, "Going to commit RXON\n" diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index 4b97371c3b42..adaa2f0097cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -319,8 +319,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, if (noa_data && pskb_expand_head(skb, 0, noa_data->length, GFP_ATOMIC) == 0) { - memcpy(skb_put(skb, noa_data->length), - noa_data->data, noa_data->length); + skb_put_data(skb, noa_data->data, noa_data->length); hdr = (struct ieee80211_hdr *)skb->data; } } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api.h b/drivers/net/wireless/intel/iwlwifi/fw/api.h new file mode 100644 index 000000000000..0e107f916ce3 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * 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) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 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. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland 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. + * + *****************************************************************************/ +#ifndef __iwl_fw_api_h__ +#define __iwl_fw_api_h__ + +/** + * DOC: Host command section + * + * A host command is a command issued by the upper layer to the fw. There are + * several versions of fw that have several APIs. The transport layer is + * completely agnostic to these differences. + * The transport does provide helper functionality (i.e. SYNC / ASYNC mode), + */ +#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) +#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) +#define SEQ_TO_INDEX(s) ((s) & 0xff) +#define INDEX_TO_SEQ(i) ((i) & 0xff) +#define SEQ_RX_FRAME cpu_to_le16(0x8000) + +/* + * those functions retrieve specific information from + * the id field in the iwl_host_cmd struct which contains + * the command id, the group id and the version of the command + * and vice versa +*/ +static inline u8 iwl_cmd_opcode(u32 cmdid) +{ + return cmdid & 0xFF; +} + +static inline u8 iwl_cmd_groupid(u32 cmdid) +{ + return ((cmdid & 0xFF00) >> 8); +} + +static inline u8 iwl_cmd_version(u32 cmdid) +{ + return ((cmdid & 0xFF0000) >> 16); +} + +static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) +{ + return opcode + (groupid << 8) + (version << 16); +} + +/* make u16 wide id out of u8 group and opcode */ +#define WIDE_ID(grp, opcode) (((grp) << 8) | (opcode)) +#define DEF_ID(opcode) ((1 << 8) | (opcode)) + +/* due to the conversion, this group is special; new groups + * should be defined in the appropriate fw-api header files + */ +#define IWL_ALWAYS_LONG_GROUP 1 + +/** + * struct iwl_cmd_header + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + */ +struct iwl_cmd_header { + u8 cmd; /* Command ID: REPLY_RXON, etc. */ + u8 group_id; + /* + * The driver sets up the sequence number to values of its choosing. + * uCode does not use this value, but passes it back to the driver + * when sending the response to each driver-originated command, so + * the driver can match the response to the command. Since the values + * don't get used by uCode, the driver may set up an arbitrary format. + * + * There is one exception: uCode sets bit 15 when it originates + * the response/notification, i.e. when the response/notification + * is not a direct response to a command sent by the driver. For + * example, uCode issues REPLY_RX when it sends a received frame + * to the driver; it is not a direct response to any driver command. + * + * The Linux driver uses the following format: + * + * 0:7 tfd index - position within TX queue + * 8:12 TX queue id + * 13:14 reserved + * 15 unsolicited RX or uCode-originated notification + */ + __le16 sequence; +} __packed; + +/** + * struct iwl_cmd_header_wide + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + * this is the wide version that contains more information about the command + * like length, version and command type + */ +struct iwl_cmd_header_wide { + u8 cmd; + u8 group_id; + __le16 sequence; + __le16 length; + u8 reserved; + u8 version; +} __packed; + +/** + * iwl_tx_queue_cfg_actions - TXQ config options + * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue + * @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format + */ +enum iwl_tx_queue_cfg_actions { + TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), + TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), +}; + +/** + * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command + * @sta_id: station id + * @tid: tid of the queue + * @flags: see &enum iwl_tx_queue_cfg_actions + * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. + * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) + * @byte_cnt_addr: address of byte count table + * @tfdq_addr: address of TFD circular buffer + */ +struct iwl_tx_queue_cfg_cmd { + u8 sta_id; + u8 tid; + __le16 flags; + __le32 cb_size; + __le64 byte_cnt_addr; + __le64 tfdq_addr; +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ + +/** + * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config + * @queue_number: queue number assigned to this RA -TID + * @flags: set on failure + * @write_pointer: initial value for write pointer + */ +struct iwl_tx_queue_cfg_rsp { + __le16 queue_number; + __le16 flags; + __le16 write_pointer; + __le16 reserved; +} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ + +/** + * struct iwl_calib_res_notif_phy_db - Receive phy db chunk after calibrations + * @type: type of the result - mostly ignored + * @length: length of the data + * @data: data, length in @length + */ +struct iwl_calib_res_notif_phy_db { + __le16 type; + __le16 length; + u8 data[]; +} __packed; + +/** + * struct iwl_phy_db_cmd - configure operational ucode + * @type: type of the data + * @length: length of the data + * @data: data, length in @length + */ +struct iwl_phy_db_cmd { + __le16 type; + __le16 length; + u8 data[]; +} __packed; + +#endif /* __iwl_fw_api_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 420c31dab263..cfebde68a391 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -116,7 +116,7 @@ enum iwl_fw_error_dump_type { /** * struct iwl_fw_error_dump_data - data for one type - * @type: %enum iwl_fw_error_dump_type + * @type: &enum iwl_fw_error_dump_type * @len: the length starting from %data * @data: the data itself */ @@ -130,7 +130,7 @@ struct iwl_fw_error_dump_data { * struct iwl_fw_error_dump_file - the layout of the header of the file * @barker: must be %IWL_FW_ERROR_DUMP_BARKER * @file_len: the length of all the file starting from %barker - * @data: array of %struct iwl_fw_error_dump_data + * @data: array of &struct iwl_fw_error_dump_data */ struct iwl_fw_error_dump_file { __le32 barker; @@ -225,7 +225,7 @@ enum iwl_fw_error_dump_mem_type { /** * struct iwl_fw_error_dump_mem - chunk of memory - * @type: %enum iwl_fw_error_dump_mem_type + * @type: &enum iwl_fw_error_dump_mem_type * @offset: the offset from which the memory was read * @data: the content of the memory */ @@ -324,7 +324,7 @@ enum iwl_fw_dbg_trigger { /** * struct iwl_fw_error_dump_trigger_desc - describes the trigger condition - * @type: %enum iwl_fw_dbg_trigger + * @type: &enum iwl_fw_dbg_trigger * @data: raw data about what happened */ struct iwl_fw_error_dump_trigger_desc { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 44419e82da1b..0fa8c473f1e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -244,10 +244,13 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of * ADD_MODIFY_STA_KEY_API_S_VER_2. * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. + * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 + * @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used * * @NUM_IWL_UCODE_TLV_API: number of bits used */ enum iwl_ucode_tlv_api { + /* API Set 0 */ IWL_UCODE_TLV_API_FRAGMENTED_SCAN = (__force iwl_ucode_tlv_api_t)8, IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18, @@ -255,6 +258,9 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_SCAN_TSF_REPORT = (__force iwl_ucode_tlv_api_t)28, IWL_UCODE_TLV_API_TKIP_MIC_KEYS = (__force iwl_ucode_tlv_api_t)29, IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30, + IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, + /* API Set 1 */ + IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ @@ -351,6 +357,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40, + IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41, IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, @@ -395,8 +402,8 @@ enum iwl_ucode_tlv_capa { #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) -/* - * Calibration control struct. +/** + * struct iwl_tlv_calib_ctrl - Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. @@ -468,7 +475,7 @@ enum iwl_fw_dbg_reg_operator { /** * struct iwl_fw_dbg_reg_op - an operation on a register * - * @op: %enum iwl_fw_dbg_reg_operator + * @op: &enum iwl_fw_dbg_reg_operator * @addr: offset of the register * @val: value */ @@ -526,7 +533,7 @@ struct iwl_fw_dbg_mem_seg_tlv { * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data * * @version: version of the TLV - currently 0 - * @monitor_mode: %enum iwl_fw_dbg_monitor_mode + * @monitor_mode: &enum iwl_fw_dbg_monitor_mode * @size_power: buffer size will be 2^(size_power + 11) * @base_reg: addr of the base addr register (PRPH) * @end_reg: addr of the end addr register (PRPH) @@ -595,15 +602,15 @@ enum iwl_fw_dbg_trigger_vif_type { /** * struct iwl_fw_dbg_trigger_tlv - a TLV that describes the trigger - * @id: %enum iwl_fw_dbg_trigger - * @vif_type: %enum iwl_fw_dbg_trigger_vif_type + * @id: &enum iwl_fw_dbg_trigger + * @vif_type: &enum iwl_fw_dbg_trigger_vif_type * @stop_conf_ids: bitmap of configurations this trigger relates to. * if the mode is %IWL_FW_DBG_TRIGGER_STOP, then if the bit corresponding * to the currently running configuration is set, the data should be * collected. * @stop_delay: how many milliseconds to wait before collecting the data * after the STOP trigger fires. - * @mode: %enum iwl_fw_dbg_trigger_mode - can be stop / start of both + * @mode: &enum iwl_fw_dbg_trigger_mode - can be stop / start of both * @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what * configuration should be applied when the triggers kicks in. * @occurrences: number of occurrences. 0 means the trigger will never fire. diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index d323b70b510a..e6bc9cb60700 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -64,12 +64,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __iwl_fw_h__ -#define __iwl_fw_h__ +#ifndef __iwl_fw_img_h__ +#define __iwl_fw_img_h__ #include <linux/types.h> -#include "iwl-fw-file.h" -#include "iwl-fw-error-dump.h" +#include "file.h" +#include "error-dump.h" /** * enum iwl_ucode_type @@ -339,4 +339,4 @@ iwl_get_ucode_image(const struct iwl_fw *fw, enum iwl_ucode_type ucode_type) return &fw->img[ucode_type]; } -#endif /* __iwl_fw_h__ */ +#endif /* __iwl_fw_img_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c index 68412ff2112e..29bb92e3df59 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c @@ -65,7 +65,7 @@ #include <linux/export.h> #include "iwl-drv.h" -#include "iwl-notif-wait.h" +#include "notif-wait.h" void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h index 368884be4e7c..368884be4e7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index a12197e3ce78..c52623cb7c2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -88,6 +88,8 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_6150, IWL_DEVICE_FAMILY_7000, IWL_DEVICE_FAMILY_8000, + IWL_DEVICE_FAMILY_9000, + IWL_DEVICE_FAMILY_A000, }; /* @@ -129,6 +131,7 @@ enum iwl_led_mode { /* Antenna presence definitions */ #define ANT_NONE 0x0 +#define ANT_INVALID 0xff #define ANT_A BIT(0) #define ANT_B BIT(1) #define ANT_C BIT(2) @@ -275,6 +278,8 @@ struct iwl_pwr_tx_backoff { * filename is constructed as fw_name_pre<api>.ucode. * @fw_name_pre_next_step: same as @fw_name_pre, only for next step * (if supported) + * @fw_name_pre_rf_next_step: same as @fw_name_pre_next_step, only for rf next + * step. Supported only in integrated solutions. * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @max_inst_size: The maximal length of the fw inst section @@ -315,6 +320,7 @@ struct iwl_pwr_tx_backoff { * @integrated: discrete or integrated * @gen2: a000 and on transport operation * @cdb: CDB support + * @ext_nvm: extended NVM format * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -325,13 +331,13 @@ struct iwl_cfg { const char *name; const char *fw_name_pre; const char *fw_name_pre_next_step; + const char *fw_name_pre_rf_next_step; /* params not likely to change within a device family */ const struct iwl_base_params *base_params; /* params likely to change within a device family */ const struct iwl_ht_params *ht_params; const struct iwl_eeprom_params *eeprom_params; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; - const char *default_nvm_file_B_step; const char *default_nvm_file_C_step; const struct iwl_tt_params *thermal_params; enum iwl_device_family device_family; @@ -362,7 +368,9 @@ struct iwl_cfg { integrated:1, use_tfh:1, gen2:1, - cdb:1; + cdb:1, + ext_nvm:1, + dbgc_supported:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; @@ -454,6 +462,7 @@ extern const struct iwl_cfg iwl9560_2ac_cfg; extern const struct iwl_cfg iwla000_2ac_cfg_hr; extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; +extern const struct iwl_cfg iwla000_2ax_cfg_hr; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index fa120fb55373..c6c1876c1ad4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -153,6 +153,10 @@ /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +/* host chicken bits */ +#define CSR_HOST_CHICKEN (CSR_BASE + 0x204) +#define CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME BIT(19) + /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) @@ -308,7 +312,7 @@ #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) #define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) -#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) @@ -316,6 +320,11 @@ #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) +/* HW RFID */ +#define CSR_HW_RFID_FLAVOR(_val) (((_val) & 0x000000F) >> 0) +#define CSR_HW_RFID_DASH(_val) (((_val) & 0x00000F0) >> 4) +#define CSR_HW_RFID_STEP(_val) (((_val) & 0x0000F00) >> 8) +#define CSR_HW_RFID_TYPE(_val) (((_val) & 0x0FFF000) >> 12) /** * hw_rev values @@ -348,7 +357,8 @@ enum { /* RF_ID value */ #define CSR_HW_RF_ID_TYPE_JF (0x00105000) -#define CSR_HW_RF_ID_TYPE_HR (0x00109000) +#define CSR_HW_RF_ID_TYPE_HR (0x0010A000) +#define CSR_HW_RF_ID_TYPE_HRCDB (0x00109000) /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h index d80312b46f16..a80e4202cd03 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h @@ -35,19 +35,20 @@ TRACE_EVENT(iwlwifi_dev_tx_data, TP_PROTO(const struct device *dev, - struct sk_buff *skb, - u8 hdr_len, size_t data_len), - TP_ARGS(dev, skb, hdr_len, data_len), + struct sk_buff *skb, u8 hdr_len), + TP_ARGS(dev, skb, hdr_len), TP_STRUCT__entry( DEV_ENTRY - __dynamic_array(u8, data, iwl_trace_data(skb) ? data_len : 0) + __dynamic_array(u8, data, + iwl_trace_data(skb) ? skb->len - hdr_len : 0) ), TP_fast_assign( DEV_ASSIGN; if (iwl_trace_data(skb)) skb_copy_bits(skb, hdr_len, - __get_dynamic_array(data), data_len); + __get_dynamic_array(data), + skb->len - hdr_len); ), TP_printk("[%s] TX frame data", __get_str(dev)) ); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h index 1dccae6532cf..4164dc1745ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h @@ -1,7 +1,7 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016-2017 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 @@ -29,6 +29,7 @@ #define __IWLWIFI_DEVICE_TRACE_IO #include <linux/tracepoint.h> +#include <linux/pci.h> #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi_io @@ -165,6 +166,29 @@ TRACE_EVENT(iwlwifi_dev_irq, TP_printk("%d", 0) ); +TRACE_EVENT(iwlwifi_dev_irq_msix, + TP_PROTO(const struct device *dev, struct msix_entry *msix_entry, + bool defirq, u32 inta_fh, u32 inta_hw), + TP_ARGS(dev, msix_entry, defirq, inta_fh, inta_hw), + TP_STRUCT__entry( + DEV_ENTRY + __field(u32, entry) + __field(u8, defirq) + __field(u32, inta_fh) + __field(u32, inta_hw) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->entry = msix_entry->entry; + __entry->defirq = defirq; + __entry->inta_fh = inta_fh; + __entry->inta_hw = inta_hw; + ), + TP_printk("entry:%d defirq:%d fh:0x%x, hw:0x%x", + __entry->entry, __entry->defirq, + __entry->inta_fh, __entry->inta_hw) +); + TRACE_EVENT(iwlwifi_dev_ict_read, TP_PROTO(const struct device *dev, u32 index, u32 value), TP_ARGS(dev, index, value), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index f02e2c89abbb..7f16dcce0995 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -2,7 +2,7 @@ * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 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 @@ -91,8 +91,8 @@ TRACE_EVENT(iwlwifi_dev_tx, TP_PROTO(const struct device *dev, struct sk_buff *skb, void *tfd, size_t tfdlen, void *buf0, size_t buf0_len, - void *buf1, size_t buf1_len), - TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len), + int hdr_len), + TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, hdr_len), TP_STRUCT__entry( DEV_ENTRY @@ -105,15 +105,20 @@ TRACE_EVENT(iwlwifi_dev_tx, * for the possible padding). */ __dynamic_array(u8, buf0, buf0_len) - __dynamic_array(u8, buf1, iwl_trace_data(skb) ? 0 : buf1_len) + __dynamic_array(u8, buf1, hdr_len > 0 && iwl_trace_data(skb) ? + 0 : skb->len - hdr_len) ), TP_fast_assign( DEV_ASSIGN; - __entry->framelen = buf0_len + buf1_len; + __entry->framelen = buf0_len; + if (hdr_len > 0) + __entry->framelen += skb->len - hdr_len; memcpy(__get_dynamic_array(tfd), tfd, tfdlen); memcpy(__get_dynamic_array(buf0), buf0, buf0_len); - if (!iwl_trace_data(skb)) - memcpy(__get_dynamic_array(buf1), buf1, buf1_len); + if (hdr_len > 0 && !iwl_trace_data(skb)) + skb_copy_bits(skb, hdr_len, + __get_dynamic_array(buf1), + skb->len - hdr_len); ), TP_printk("[%s] TX %.2x (%zu bytes)", __get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0], diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 5cfacb0bca84..6fdb5921e17f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -76,7 +76,7 @@ #include "iwl-trans.h" #include "iwl-op-mode.h" #include "iwl-agn-hw.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-config.h" #include "iwl-modparams.h" @@ -215,9 +215,13 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) char tag[8]; const char *fw_pre_name; - if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 && CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_B_STEP) fw_pre_name = cfg->fw_name_pre_next_step; + else if (drv->trans->cfg->integrated && + CSR_HW_RFID_STEP(drv->trans->hw_rf_id) == SILICON_B_STEP && + cfg->fw_name_pre_rf_next_step) + fw_pre_name = cfg->fw_name_pre_rf_next_step; else fw_pre_name = cfg->fw_name_pre; @@ -1611,11 +1615,11 @@ void iwl_drv_stop(struct iwl_drv *drv) /* shared module parameters */ struct iwl_mod_params iwlwifi_mod_params = { - .restart_fw = true, + .fw_restart = true, .bt_coex_active = true, .power_level = IWL_POWER_INDEX_1, .d0i3_disable = true, - .d0i3_entry_delay = 1000, + .d0i3_timeout = 1000, .uapsd_disable = IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT, /* the rest are 0 by default */ }; @@ -1707,7 +1711,7 @@ module_param_named(debug, iwlwifi_mod_params.debug_level, uint, MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO); +module_param_named(swcrypto, iwlwifi_mod_params.swcrypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); MODULE_PARM_DESC(11n_disable, @@ -1716,10 +1720,10 @@ module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size, int, S_IRUGO); MODULE_PARM_DESC(amsdu_size, "amsdu size 0: 12K for multi Rx queue devices, 4K for other devices 1:4K 2:8K 3:12K (default 0)"); -module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO); +module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)"); -module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, +module_param_named(antenna_coupling, iwlwifi_mod_params.antenna_coupling, int, S_IRUGO); MODULE_PARM_DESC(antenna_coupling, "specify antenna coupling in dB (default: 0 dB)"); @@ -1778,7 +1782,7 @@ module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO); MODULE_PARM_DESC(fw_monitor, "firmware monitor - to debug FW (default: false - needs lots of memory)"); -module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_entry_delay, +module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_timeout, uint, S_IRUGO); MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 6c537e04864e..1f8a2eeb7dff 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -79,12 +79,12 @@ #define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ -#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x) (x & 0xF) -#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x) ((x >> 4) & 0xF) -#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x) ((x >> 8) & 0xF) -#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x) ((x >> 12) & 0xFFF) -#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF) -#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF) +#define EXT_NVM_RF_CFG_FLAVOR_MSK(x) ((x) & 0xF) +#define EXT_NVM_RF_CFG_DASH_MSK(x) (((x) >> 4) & 0xF) +#define EXT_NVM_RF_CFG_STEP_MSK(x) (((x) >> 8) & 0xF) +#define EXT_NVM_RF_CFG_TYPE_MSK(x) (((x) >> 12) & 0xFFF) +#define EXT_NVM_RF_CFG_TX_ANT_MSK(x) (((x) >> 24) & 0xF) +#define EXT_NVM_RF_CFG_RX_ANT_MSK(x) (((x) >> 28) & 0xF) /** * DOC: Driver system flows - drv component diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index e04a91d70a15..b33888991b94 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -121,15 +121,6 @@ struct iwl_nvm_data * iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg, const u8 *eeprom, size_t eeprom_size); -/** - * iwl_free_nvm_data - free NVM data - * @data: the data to free - */ -static inline void iwl_free_nvm_data(struct iwl_nvm_data *data) -{ - kfree(data); -} - int iwl_nvm_check_version(struct iwl_nvm_data *data, struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 62f9fe926d78..66e5db41e559 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 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 @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,6 +66,7 @@ #define __iwl_fh_h__ #include <linux/types.h> +#include <linux/bitfield.h> /****************************/ /* Flow Handler Definitions */ @@ -77,6 +78,8 @@ */ #define FH_MEM_LOWER_BOUND (0x1000) #define FH_MEM_UPPER_BOUND (0x2000) +#define FH_MEM_LOWER_BOUND_GEN2 (0xa06000) +#define FH_MEM_UPPER_BOUND_GEN2 (0xa08000) /** * Keep-Warm (KW) buffer base address. @@ -476,13 +479,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define RFH_GEN_CFG 0xA09800 #define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0) #define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1) -#define RFH_GEN_CFG_RB_CHUNK_SIZE_POS 4 +#define RFH_GEN_CFG_RB_CHUNK_SIZE BIT(4) #define RFH_GEN_CFG_RB_CHUNK_SIZE_128 1 #define RFH_GEN_CFG_RB_CHUNK_SIZE_64 0 -#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00 -#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8 - -#define DEFAULT_RXQ_NUM 0 +/* the driver assumes everywhere that the default RXQ is 0 */ +#define RFH_GEN_CFG_DEFAULT_RXQ_NUM 0xF00 +#define RFH_GEN_CFG_VAL(_n, _v) FIELD_PREP(RFH_GEN_CFG_ ## _n, _v) /* end of 9000 rx series registers */ @@ -653,6 +655,17 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) { return (sizeof(addr) > sizeof(u32) ? upper_32_bits(addr) : 0) & 0xF; } + +/** + * enum iwl_tfd_tb_hi_n_len - TB hi_n_len bits + * @TB_HI_N_LEN_ADDR_HI_MSK: high 4 bits (to make it 36) of DMA address + * @TB_HI_N_LEN_LEN_MSK: length of the TB + */ +enum iwl_tfd_tb_hi_n_len { + TB_HI_N_LEN_ADDR_HI_MSK = 0xf, + TB_HI_N_LEN_LEN_MSK = 0xfff0, +}; + /** * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor * @@ -660,8 +673,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) * * @lo: low [31:0] portion of the dma address of TX buffer * every even is unaligned on 16 bit boundary - * @hi_n_len 0-3 [35:32] portion of dma - * 4-15 length of the tx buffer + * @hi_n_len: &enum iwl_tfd_tb_hi_n_len */ struct iwl_tfd_tb { __le32 lo; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 9c8b09cf1f7b..c527b8c10370 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -241,12 +241,12 @@ IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); void iwl_force_nmi(struct iwl_trans *trans) { - if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) { iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_DRV); iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_HW); - } else if (trans->cfg->gen2) { + } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) { iwl_write_prph(trans, UREG_NIC_SET_NMI_DRIVER, DEVICE_SET_NMI_8000_VAL); } else { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 4d32b10fe50c..a41c46e63eb1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -102,32 +102,32 @@ enum iwl_uapsd_disable { * * Holds the module parameters * - * @sw_crypto: using hardware encryption, default = 0 + * @swcrypto: using hardware encryption, default = 0 * @disable_11n: disable 11n capabilities, default = 0, * use IWL_[DIS,EN]ABLE_HT_* constants * @amsdu_size: See &enum iwl_amsdu_size. - * @restart_fw: restart firmware, default = 1 + * @fw_restart: restart firmware, default = 1 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @power_save: enable power save, default = false * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* - * @ant_coupling: antenna coupling in dB, default = 0 + * @antenna_coupling: antenna coupling in dB, default = 0 * @nvm_file: specifies a external NVM file - * @uapsd_disable: disable U-APSD, see %enum iwl_uapsd_disable, default = + * @uapsd_disable: disable U-APSD, see &enum iwl_uapsd_disable, default = * IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT * @d0i3_disable: disable d0i3, default = 1, - * @d0i3_entry_delay: time to wait after no refs are taken before + * @d0i3_timeout: time to wait after no refs are taken before * entering D0i3 (in msecs) * @lar_disable: disable LAR (regulatory), default = 0 * @fw_monitor: allow to use firmware monitor * @disable_11ac: disable VHT capabilities, default = false. */ struct iwl_mod_params { - int sw_crypto; + int swcrypto; unsigned int disable_11n; int amsdu_size; - bool restart_fw; + bool fw_restart; bool bt_coex_active; int led_mode; bool power_save; @@ -135,11 +135,11 @@ struct iwl_mod_params { #ifdef CONFIG_IWLWIFI_DEBUG u32 debug_level; #endif - int ant_coupling; + int antenna_coupling; char *nvm_file; u32 uapsd_disable; bool d0i3_disable; - unsigned int d0i3_entry_delay; + unsigned int d0i3_timeout; bool lar_disable; bool fw_monitor; bool disable_11ac; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 721ae6bef5da..5c08f4d40f6a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -94,30 +94,21 @@ enum wkp_nvm_offsets { XTAL_CALIB = 0x316 - NVM_CALIB_SECTION }; -enum family_8000_nvm_offsets { +enum ext_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ - HW_ADDR0_WFPM_FAMILY_8000 = 0x12, - HW_ADDR1_WFPM_FAMILY_8000 = 0x16, - HW_ADDR0_PCIE_FAMILY_8000 = 0x8A, - HW_ADDR1_PCIE_FAMILY_8000 = 0x8E, - MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1, + MAC_ADDRESS_OVERRIDE_EXT_NVM = 1, /* NVM SW-Section offset (in words) definitions */ - NVM_SW_SECTION_FAMILY_8000 = 0x1C0, - NVM_VERSION_FAMILY_8000 = 0, - RADIO_CFG_FAMILY_8000 = 0, + NVM_VERSION_EXT_NVM = 0, + RADIO_CFG_FAMILY_EXT_NVM = 0, SKU_FAMILY_8000 = 2, N_HW_ADDRS_FAMILY_8000 = 3, /* NVM REGULATORY -Section offset (in words) definitions */ - NVM_CHANNELS_FAMILY_8000 = 0, - NVM_LAR_OFFSET_FAMILY_8000_OLD = 0x4C7, - NVM_LAR_OFFSET_FAMILY_8000 = 0x507, - NVM_LAR_ENABLED_FAMILY_8000 = 0x7, - - /* NVM calibration section offset (in words) definitions */ - NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8, - XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000 + NVM_CHANNELS_EXTENDED = 0, + NVM_LAR_OFFSET_OLD = 0x4C7, + NVM_LAR_OFFSET = 0x507, + NVM_LAR_ENABLED = 0x7, }; /* SKU Capabilities (actual values from NVM definition) */ @@ -141,7 +132,7 @@ static const u8 iwl_nvm_channels[] = { 149, 153, 157, 161, 165 }; -static const u8 iwl_nvm_channels_family_8000[] = { +static const u8 iwl_ext_nvm_channels[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ @@ -151,9 +142,9 @@ static const u8 iwl_nvm_channels_family_8000[] = { }; #define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) -#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000) +#define IWL_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels) #define NUM_2GHZ_CHANNELS 14 -#define NUM_2GHZ_CHANNELS_FAMILY_8000 14 +#define NUM_2GHZ_CHANNELS_EXT 14 #define FIRST_2GHZ_HT_MINUS 5 #define LAST_2GHZ_HT_PLUS 9 #define LAST_5GHZ_HT 165 @@ -219,7 +210,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, u32 flags = IEEE80211_CHAN_NO_HT40; u32 last_5ghz_ht = LAST_5GHZ_HT; - if (cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (cfg->ext_nvm) last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { @@ -273,14 +264,14 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, num_2ghz_channels; const u8 *nvm_chan; - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!cfg->ext_nvm) { num_of_ch = IWL_NUM_CHANNELS; nvm_chan = &iwl_nvm_channels[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS; } else { - num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000; - nvm_chan = &iwl_nvm_channels_family_8000[0]; - num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000; + num_of_ch = IWL_NUM_CHANNELS_EXT; + nvm_chan = &iwl_ext_nvm_channels[0]; + num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT; } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { @@ -479,7 +470,7 @@ IWL_EXPORT_SYMBOL(iwl_init_sbands); static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, const __le16 *phy_sku) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + SKU); return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000)); @@ -487,20 +478,20 @@ static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + NVM_VERSION); else return le32_to_cpup((__le32 *)(nvm_sw + - NVM_VERSION_FAMILY_8000)); + NVM_VERSION_EXT_NVM)); } static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw, const __le16 *phy_sku) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + RADIO_CFG); - return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_8000)); + return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM)); } @@ -508,7 +499,7 @@ static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw) { int n_hw_addr; - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + N_HW_ADDRS); n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)); @@ -520,7 +511,7 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, struct iwl_nvm_data *data, u32 radio_cfg) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!cfg->ext_nvm) { data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); @@ -529,12 +520,12 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, } /* set the radio configuration for family 8000 */ - data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg); - data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg); - data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg); - data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg); - data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg); - data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); + data->radio_cfg_type = EXT_NVM_RF_CFG_TYPE_MSK(radio_cfg); + data->radio_cfg_step = EXT_NVM_RF_CFG_STEP_MSK(radio_cfg); + data->radio_cfg_dash = EXT_NVM_RF_CFG_DASH_MSK(radio_cfg); + data->radio_cfg_pnum = EXT_NVM_RF_CFG_FLAVOR_MSK(radio_cfg); + data->valid_tx_ant = EXT_NVM_RF_CFG_TX_ANT_MSK(radio_cfg); + data->valid_rx_ant = EXT_NVM_RF_CFG_RX_ANT_MSK(radio_cfg); } static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) @@ -587,7 +578,7 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, }; hw_addr = (const u8 *)(mac_override + - MAC_ADDRESS_OVERRIDE_FAMILY_8000); + MAC_ADDRESS_OVERRIDE_EXT_NVM); /* * Store the MAC address from MAO section. @@ -629,7 +620,7 @@ static int iwl_set_hw_address(struct iwl_trans *trans, { if (cfg->mac_addr_from_csr) { iwl_set_hw_address_from_csr(trans, data); - } else if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + } else if (!cfg->ext_nvm) { const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR); /* The byte order is little endian 16 bit, meaning 214365 */ @@ -649,6 +640,8 @@ static int iwl_set_hw_address(struct iwl_trans *trans, return -EINVAL; } + IWL_INFO(trans, "base HW address: %pM\n", data->hw_addr); + return 0; } @@ -666,7 +659,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, u16 lar_config; const __le16 *ch_section; - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) data = kzalloc(sizeof(*data) + sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, @@ -674,7 +667,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, else data = kzalloc(sizeof(*data) + sizeof(struct ieee80211_channel) * - IWL_NUM_CHANNELS_FAMILY_8000, + IWL_NUM_CHANNELS_EXT, GFP_KERNEL); if (!data) return NULL; @@ -700,7 +693,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!cfg->ext_nvm) { /* Checking for required sections */ if (!nvm_calib) { IWL_ERR(trans, @@ -715,14 +708,14 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, ch_section = &nvm_sw[NVM_CHANNELS]; } else { u16 lar_offset = data->nvm_version < 0xE39 ? - NVM_LAR_OFFSET_FAMILY_8000_OLD : - NVM_LAR_OFFSET_FAMILY_8000; + NVM_LAR_OFFSET_OLD : + NVM_LAR_OFFSET; lar_config = le16_to_cpup(regulatory + lar_offset); data->lar_enabled = !!(lar_config & - NVM_LAR_ENABLED_FAMILY_8000); + NVM_LAR_ENABLED); lar_enabled = data->lar_enabled; - ch_section = ®ulatory[NVM_CHANNELS_FAMILY_8000]; + ch_section = ®ulatory[NVM_CHANNELS_EXTENDED]; } /* If no valid mac address was found - bail out */ @@ -746,7 +739,7 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, u32 flags = NL80211_RRF_NO_HT40; u32 last_5ghz_ht = LAST_5GHZ_HT; - if (cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (cfg->ext_nvm) last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; if (ch_idx < NUM_2GHZ_CHANNELS && @@ -793,8 +786,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, { int ch_idx; u16 ch_flags, prev_ch_flags = 0; - const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? - iwl_nvm_channels_family_8000 : iwl_nvm_channels; + const u8 *nvm_chan = cfg->ext_nvm ? + iwl_ext_nvm_channels : iwl_nvm_channels; struct ieee80211_regdomain *regd; int size_of_regd; struct ieee80211_reg_rule *rule; @@ -802,8 +795,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int center_freq, prev_center_freq = 0; int valid_rules = 0; bool new_rule; - int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? - IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS; + int max_num_ch = cfg->ext_nvm ? + IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS; if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) return ERR_PTR(-EINVAL); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c index 2893826d7d2b..b7cd813ba70f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c @@ -112,30 +112,12 @@ enum iwl_phy_db_section_type { #define PHY_DB_CMD 0x6c -/* - * phy db - configure operational ucode - */ -struct iwl_phy_db_cmd { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - /* for parsing of tx power channel group data that comes from the firmware*/ struct iwl_phy_db_chg_txp { __le32 space; __le16 max_channel_idx; } __packed; -/* - * phy db - Receive phy db chunk after calibrations - */ -struct iwl_calib_res_notif_phy_db { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) { struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 77efbb78e867..6772c59b7764 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -66,6 +66,7 @@ #ifndef __iwl_prph_h__ #define __iwl_prph_h__ +#include <linux/bitfield.h> /* * Registers in this file are internal, not PCI bus memory mapped. @@ -247,14 +248,14 @@ #define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) #define SCD_QUEUE_STTS_REG_MSK (0x017F0000) -#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8) -#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) -#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) -#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) -#define SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) -#define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) +#define SCD_QUEUE_CTX_REG1_CREDIT (0x00FFFF00) +#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT (0xFF000000) +#define SCD_QUEUE_CTX_REG1_VAL(_n, _v) FIELD_PREP(SCD_QUEUE_CTX_REG1_ ## _n, _v) + +#define SCD_QUEUE_CTX_REG2_WIN_SIZE (0x0000007F) +#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT (0x007F0000) +#define SCD_QUEUE_CTX_REG2_VAL(_n, _v) FIELD_PREP(SCD_QUEUE_CTX_REG2_ ## _n, _v) + #define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0) #define SCD_GP_CTRL_AUTO_ACTIVE_MODE BIT(18) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 0bde26bab15d..784bdd0ed233 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -102,6 +102,8 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, if (!trans->dev_cmd_pool) return NULL; + WARN_ON(!ops->wait_txq_empty && !ops->wait_tx_queues_empty); + return trans; } @@ -115,7 +117,7 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) int ret; if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status))) + test_bit(STATUS_RFKILL_OPMODE, &trans->status))) return -ERFKILL; if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) @@ -141,6 +143,9 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if (!(cmd->flags & CMD_ASYNC)) lock_map_release(&trans->sync_cmd_lockdep_map); + if (WARN_ON((cmd->flags & CMD_WANT_SKB) && !ret && !cmd->resp_pkt)) + return -EIO; + return ret; } IWL_EXPORT_SYMBOL(iwl_trans_send_cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0ebfdbb22992..eb6842abb4c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -74,8 +74,9 @@ #include "iwl-debug.h" #include "iwl-config.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-op-mode.h" +#include "fw/api.h" /** * DOC: Transport layer - what is it ? @@ -111,104 +112,6 @@ * 6) Eventually, the free function will be called. */ -/** - * DOC: Host command section - * - * A host command is a command issued by the upper layer to the fw. There are - * several versions of fw that have several APIs. The transport layer is - * completely agnostic to these differences. - * The transport does provide helper functionality (i.e. SYNC / ASYNC mode), - */ -#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) -#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) -#define SEQ_TO_INDEX(s) ((s) & 0xff) -#define INDEX_TO_SEQ(i) ((i) & 0xff) -#define SEQ_RX_FRAME cpu_to_le16(0x8000) - -/* - * those functions retrieve specific information from - * the id field in the iwl_host_cmd struct which contains - * the command id, the group id and the version of the command - * and vice versa -*/ -static inline u8 iwl_cmd_opcode(u32 cmdid) -{ - return cmdid & 0xFF; -} - -static inline u8 iwl_cmd_groupid(u32 cmdid) -{ - return ((cmdid & 0xFF00) >> 8); -} - -static inline u8 iwl_cmd_version(u32 cmdid) -{ - return ((cmdid & 0xFF0000) >> 16); -} - -static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) -{ - return opcode + (groupid << 8) + (version << 16); -} - -/* make u16 wide id out of u8 group and opcode */ -#define WIDE_ID(grp, opcode) ((grp << 8) | opcode) -#define DEF_ID(opcode) ((1 << 8) | (opcode)) - -/* due to the conversion, this group is special; new groups - * should be defined in the appropriate fw-api header files - */ -#define IWL_ALWAYS_LONG_GROUP 1 - -/** - * struct iwl_cmd_header - * - * This header format appears in the beginning of each command sent from the - * driver, and each response/notification received from uCode. - */ -struct iwl_cmd_header { - u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 group_id; - /* - * The driver sets up the sequence number to values of its choosing. - * uCode does not use this value, but passes it back to the driver - * when sending the response to each driver-originated command, so - * the driver can match the response to the command. Since the values - * don't get used by uCode, the driver may set up an arbitrary format. - * - * There is one exception: uCode sets bit 15 when it originates - * the response/notification, i.e. when the response/notification - * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_RX when it sends a received frame - * to the driver; it is not a direct response to any driver command. - * - * The Linux driver uses the following format: - * - * 0:7 tfd index - position within TX queue - * 8:12 TX queue id - * 13:14 reserved - * 15 unsolicited RX or uCode-originated notification - */ - __le16 sequence; -} __packed; - -/** - * struct iwl_cmd_header_wide - * - * This header format appears in the beginning of each command sent from the - * driver, and each response/notification received from uCode. - * this is the wide version that contains more information about the command - * like length, version and command type - */ -struct iwl_cmd_header_wide { - u8 cmd; - u8 group_id; - __le16 sequence; - __le16 length; - u8 reserved; - u8 version; -} __packed; - #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 @@ -308,7 +211,7 @@ struct iwl_device_cmd { #define IWL_MAX_CMD_TBS_PER_TFD 2 /** - * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command + * enum iwl_hcmd_dataflag - flag for each one of the chunks of the command * * @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's * ring. The transport layer doesn't map the command's buffer to DMA, but @@ -419,7 +322,8 @@ enum iwl_d3_status { * @STATUS_DEVICE_ENABLED: APM is enabled * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up) * @STATUS_INT_ENABLED: interrupts are enabled - * @STATUS_RFKILL: the HW RFkill switch is in KILL position + * @STATUS_RFKILL_HW: the actual HW state of the RF-kill switch + * @STATUS_RFKILL_OPMODE: RF-kill state reported to opmode * @STATUS_FW_ERROR: the fw is in error state * @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands * are sent @@ -431,7 +335,8 @@ enum iwl_trans_status { STATUS_DEVICE_ENABLED, STATUS_TPOWER_PMI, STATUS_INT_ENABLED, - STATUS_RFKILL, + STATUS_RFKILL_HW, + STATUS_RFKILL_OPMODE, STATUS_FW_ERROR, STATUS_TRANS_GOING_IDLE, STATUS_TRANS_IDLE, @@ -533,44 +438,6 @@ struct iwl_trans_txq_scd_cfg { int frame_limit; }; -/* Available options for &struct iwl_tx_queue_cfg_cmd */ -enum iwl_tx_queue_cfg_actions { - TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), - TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), -}; - -/** - * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command - * @sta_id: station id - * @tid: tid of the queue - * @flags: Bit 0 - on enable, off - disable, Bit 1 - short TFD format - * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. - * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) - * @byte_cnt_addr: address of byte count table - * @tfdq_addr: address of TFD circular buffer - */ -struct iwl_tx_queue_cfg_cmd { - u8 sta_id; - u8 tid; - __le16 flags; - __le32 cb_size; - __le64 byte_cnt_addr; - __le64 tfdq_addr; -} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ - -/** - * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config - * @queue_number: queue number assigned to this RA -TID - * @flags: set on failure - * @write_pointer: initial value for write pointer - */ -struct iwl_tx_queue_cfg_rsp { - __le16 queue_number; - __le16 flags; - __le16 write_pointer; - __le16 reserved; -} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ - /** * struct iwl_trans_ops - transport specific operations * @@ -615,11 +482,14 @@ struct iwl_tx_queue_cfg_rsp { * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before * this one. The op_mode must not configure the HCMD queue. The scheduler * configuration may be %NULL, in which case the hardware will not be - * configured. May sleep. + * configured. If true is returned, the operation mode needs to increment + * the sequence number of the packets routed to this queue because of a + * hardware scheduler bug. May sleep. * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic * @txq_set_shared_mode: change Tx queue shared/unshared marking - * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. + * @wait_tx_queues_empty: wait until tx queues are empty. May sleep. + * @wait_txq_empty: wait until specific tx queue is empty. May sleep. * @freeze_txq_timer: prevents the timer of the queue from firing until the * queue is set to awake. Must be atomic. * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note @@ -676,7 +546,7 @@ struct iwl_trans_ops { void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, struct sk_buff_head *skbs); - void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, + bool (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int queue_wdg_timeout); void (*txq_disable)(struct iwl_trans *trans, int queue, @@ -692,6 +562,7 @@ struct iwl_trans_ops { bool shared); int (*wait_tx_queues_empty)(struct iwl_trans *trans, u32 txq_bm); + int (*wait_txq_empty)(struct iwl_trans *trans, int queue); void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, bool freeze); void (*block_txq_ptrs)(struct iwl_trans *trans, bool block); @@ -1041,13 +912,7 @@ iwl_trans_dump_data(struct iwl_trans *trans, static inline struct iwl_device_cmd * iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) { - struct iwl_device_cmd *dev_cmd_ptr = - kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC); - - if (unlikely(dev_cmd_ptr == NULL)) - return NULL; - - return dev_cmd_ptr; + return kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC); } int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); @@ -1089,7 +954,7 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, trans->ops->txq_disable(trans, queue, configure_scd); } -static inline void +static inline bool iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int queue_wdg_timeout) @@ -1098,10 +963,11 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return; + return false; } - trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); + return trans->ops->txq_enable(trans, queue, ssn, + cfg, queue_wdg_timeout); } static inline void @@ -1198,6 +1064,9 @@ static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans, static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs) { + if (WARN_ON_ONCE(!trans->ops->wait_tx_queues_empty)) + return -ENOTSUPP; + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); return -EIO; @@ -1206,6 +1075,19 @@ static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, return trans->ops->wait_tx_queues_empty(trans, txqs); } +static inline int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue) +{ + if (WARN_ON_ONCE(!trans->ops->wait_txq_empty)) + return -ENOTSUPP; + + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { + IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return -EIO; + } + + return trans->ops->wait_txq_empty(trans, queue); +} + static inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) { trans->ops->write8(trans, ofs, val); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 49b4418e6c35..34dd5c40ce77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -406,7 +406,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) return ret; } -int iwl_send_bt_init_conf(struct iwl_mvm *mvm) +int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm) { struct iwl_bt_coex_cmd bt_cmd = {}; u32 mode; @@ -914,7 +914,8 @@ void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - u32 ant_isolation = le32_to_cpup((void *)pkt->data); + struct iwl_mvm_antenna_coupling_notif *notif = (void *)pkt->data; + u32 ant_isolation = le32_to_cpu(notif->isolation); struct iwl_bt_coex_corun_lut_update_cmd cmd = {}; u8 __maybe_unused lower_bound, upper_bound; u8 lut; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 4eeb6b78d952..6fda8627b726 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -110,6 +110,7 @@ #define IWL_MVM_TOF_IS_RESPONDER 0 #define IWL_MVM_SW_TX_CSUM_OFFLOAD 0 #define IWL_MVM_HW_CSUM_DISABLE 0 +#define IWL_MVM_PARSE_NVM 0 #define IWL_MVM_COLLECT_FW_ERR_DUMP 1 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 119a3bd92c50..5de19ea10575 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 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 @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -83,7 +83,7 @@ void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (iwlwifi_mod_params.sw_crypto) + if (iwlwifi_mod_params.swcrypto) return; mutex_lock(&mvm->mutex); @@ -1054,7 +1054,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, return ret; } - if (!iwlwifi_mod_params.sw_crypto) { + if (!iwlwifi_mod_params.swcrypto) { /* * This needs to be unlocked due to lock ordering * constraints. Since we're in the suspend path @@ -1280,8 +1280,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (!unified_image) { iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); - if (mvm->restart_fw > 0) { - mvm->restart_fw--; + if (mvm->fw_restart > 0) { + mvm->fw_restart--; ieee80211_restart_hw(mvm->hw); } } @@ -1431,7 +1431,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, if (!pkt) goto report; - memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen); + skb_put_data(pkt, pktdata, hdrlen); pktdata += hdrlen; pktsize -= hdrlen; @@ -1463,7 +1463,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, pktsize -= ivlen + icvlen; pktdata += ivlen; - memcpy(skb_put(pkt, pktsize), pktdata, pktsize); + skb_put_data(pkt, pktdata, pktsize); if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) goto report; @@ -1795,12 +1795,6 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ERR_PTR(ret); } - /* RF-kill already asserted again... */ - if (!cmd.resp_pkt) { - fw_status = ERR_PTR(-ERFKILL); - goto out_free_resp; - } - status_size = sizeof(*fw_status); len = iwl_rx_packet_payload_len(cmd.resp_pkt); @@ -1925,12 +1919,6 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, return ret; } - /* RF-kill already asserted again... */ - if (!cmd.resp_pkt) { - ret = -ERFKILL; - goto out_free_resp; - } - len = iwl_rx_packet_payload_len(cmd.resp_pkt); if (len < sizeof(*query)) { IWL_ERR(mvm, "Invalid scan offload profiles query response!\n"); @@ -2087,9 +2075,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) bool keep = false; bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - - u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | - CMD_WAKE_UP_TRANS; + bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_D0I3_END_FIRST); mutex_lock(&mvm->mutex); @@ -2110,6 +2097,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) /* query SRAM first in case we want event logging */ iwl_mvm_read_d3_sram(mvm); + if (d0i3_first) { + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); + if (ret < 0) { + IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n", + ret); + goto err; + } + } + /* * Query the current location and source from the D3 firmware so we * can play it back when we re-intiailize the D0 firmware @@ -2155,9 +2151,14 @@ out_iterate: iwl_mvm_d3_disconnect_iter, keep ? vif : NULL); out: + /* no need to reset the device in unified images, if successful */ if (unified_image && !ret) { - ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); - if (!ret) /* D3 ended successfully - no need to reset device */ + /* nothing else to do if we already sent D0I3_END_CMD */ + if (d0i3_first) + return 0; + + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); + if (!ret) return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 5d475b4850ae..a7ac281e5cde 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 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 @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1304,11 +1304,11 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file, char buf[30] = {}; int len; - len = snprintf(buf, sizeof(buf) - 1, - "traffic=%d\ndbgfs=%d\nvcmd=%d\n", - mvmvif->low_latency_traffic, - mvmvif->low_latency_dbgfs, - mvmvif->low_latency_vcmd); + len = scnprintf(buf, sizeof(buf) - 1, + "traffic=%d\ndbgfs=%d\nvcmd=%d\n", + mvmvif->low_latency_traffic, + mvmvif->low_latency_dbgfs, + mvmvif->low_latency_vcmd); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -1385,10 +1385,12 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file, struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); char buf[8]; + int len; - snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo); + len = scnprintf(buf, sizeof(buf), "0x%04x\n", + mvmvif->mvm->dbgfs_rx_phyinfo); - return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } static void iwl_dbgfs_quota_check(void *data, u8 *mac, @@ -1439,7 +1441,7 @@ static ssize_t iwl_dbgfs_quota_min_read(struct file *file, char buf[10]; int len; - len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); + len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 402846650cbe..c1c9c489edc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 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 @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,7 +73,7 @@ #include "sta.h" #include "iwl-io.h" #include "debugfs.h" -#include "iwl-fw-error-dump.h" +#include "fw/error-dump.h" static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, char __user *user_buf, @@ -82,7 +83,8 @@ static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, char buf[16]; int pos, budget; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -102,7 +104,8 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, { int ret; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -116,18 +119,30 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { int ret; - u32 scd_q_msk; + u32 flush_arg; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; - if (sscanf(buf, "%x", &scd_q_msk) != 1) + if (kstrtou32(buf, 0, &flush_arg)) return -EINVAL; - IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk); + if (iwl_mvm_has_new_tx_api(mvm)) { + IWL_DEBUG_TX_QUEUES(mvm, + "FLUSHING all tids queues on sta_id = %d\n", + flush_arg); + mutex_lock(&mvm->mutex); + ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count; + mutex_unlock(&mvm->mutex); + return ret; + } + + IWL_DEBUG_TX_QUEUES(mvm, "FLUSHING queues mask to flush = 0x%x\n", + flush_arg); mutex_lock(&mvm->mutex); - ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, 0) ? : count; + ret = iwl_mvm_flush_tx_path(mvm, flush_arg, 0) ? : count; mutex_unlock(&mvm->mutex); return ret; @@ -139,7 +154,8 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, struct iwl_mvm_sta *mvmsta; int sta_id, drain, ret; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) @@ -172,7 +188,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t ret; u8 *ptr; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EINVAL; /* default is to dump the entire data segment */ @@ -205,7 +221,7 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, u32 offset, len; u32 img_offset, img_len; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EINVAL; img = &mvm->fw->img[mvm->cur_ucode]; @@ -258,7 +274,7 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, { int temperature; - if (!mvm->ucode_loaded && !mvm->temperature_test) + if (!iwl_mvm_firmware_running(mvm) && !mvm->temperature_test) return -EIO; if (kstrtoint(buf, 10, &temperature)) @@ -305,7 +321,7 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, int pos, ret; s32 temp; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EIO; mutex_lock(&mvm->mutex); @@ -320,6 +336,49 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +#ifdef CONFIG_ACPI +static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + char buf[256]; + int pos = 0; + int bufsz = sizeof(buf); + int tbl_idx; + u8 *value; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + + mutex_lock(&mvm->mutex); + tbl_idx = iwl_mvm_get_sar_geo_profile(mvm); + if (tbl_idx < 0) { + mutex_unlock(&mvm->mutex); + return tbl_idx; + } + + if (!tbl_idx) { + pos = scnprintf(buf, bufsz, + "SAR geographic profile disabled\n"); + } else { + value = &mvm->geo_profiles[tbl_idx - 1].values[0]; + + pos += scnprintf(buf + pos, bufsz - pos, + "Use geographic profile %d\n", tbl_idx); + pos += scnprintf(buf + pos, bufsz - pos, + "2.4GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n", + value[1], value[2], value[0]); + pos += scnprintf(buf + pos, bufsz - pos, + "5.2GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n", + value[4], value[5], value[3]); + } + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} +#endif + static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -371,7 +430,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, { int ret, val; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EIO; if (!strncmp("disable_power_off_d0=", buf, 21)) { @@ -583,7 +642,11 @@ iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, mvm->bt_force_ant_mode = bt_force_ant_mode; IWL_DEBUG_COEX(mvm, "Force mode: %s\n", modes_str[mvm->bt_force_ant_mode]); - ret = iwl_send_bt_init_conf(mvm); + + if (iwl_mvm_firmware_running(mvm)) + ret = iwl_mvm_send_bt_init_conf(mvm); + else + ret = 0; out: mutex_unlock(&mvm->mutex); @@ -605,15 +668,15 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, int pos = 0; char *buf; int ret; - /* 43 is the size of each data line, 33 is the size of each header */ - size_t bufsz = - ((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) + - (4 * 33) + 1; + size_t bufsz; - struct mvm_statistics_rx_phy *ofdm; - struct mvm_statistics_rx_phy *cck; - struct mvm_statistics_rx_non_phy *general; - struct mvm_statistics_rx_ht_phy *ht; + if (iwl_mvm_has_new_rx_stats_api(mvm)) + bufsz = ((sizeof(struct mvm_statistics_rx) / + sizeof(__le32)) * 43) + (4 * 33) + 1; + else + /* 43 = size of each data line; 33 = size of each header */ + bufsz = ((sizeof(struct mvm_statistics_rx_v3) / + sizeof(__le32)) * 43) + (4 * 33) + 1; buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) @@ -621,96 +684,157 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, mutex_lock(&mvm->mutex); - ofdm = &mvm->rx_stats.ofdm; - cck = &mvm->rx_stats.cck; - general = &mvm->rx_stats.general; - ht = &mvm->rx_stats.ofdm_ht; - pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - OFDM"); - PRINT_STATS_LE32(ofdm, ina_cnt); - PRINT_STATS_LE32(ofdm, fina_cnt); - PRINT_STATS_LE32(ofdm, plcp_err); - PRINT_STATS_LE32(ofdm, crc32_err); - PRINT_STATS_LE32(ofdm, overrun_err); - PRINT_STATS_LE32(ofdm, early_overrun_err); - PRINT_STATS_LE32(ofdm, crc32_good); - PRINT_STATS_LE32(ofdm, false_alarm_cnt); - PRINT_STATS_LE32(ofdm, fina_sync_err_cnt); - PRINT_STATS_LE32(ofdm, sfd_timeout); - PRINT_STATS_LE32(ofdm, fina_timeout); - PRINT_STATS_LE32(ofdm, unresponded_rts); - PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); - PRINT_STATS_LE32(ofdm, sent_ack_cnt); - PRINT_STATS_LE32(ofdm, sent_cts_cnt); - PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); - PRINT_STATS_LE32(ofdm, dsp_self_kill); - PRINT_STATS_LE32(ofdm, mh_format_err); - PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum); - PRINT_STATS_LE32(ofdm, reserved); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_phy_v2 *ofdm = &mvm->rx_stats_v3.ofdm; + + PRINT_STATS_LE32(ofdm, ina_cnt); + PRINT_STATS_LE32(ofdm, fina_cnt); + PRINT_STATS_LE32(ofdm, plcp_err); + PRINT_STATS_LE32(ofdm, crc32_err); + PRINT_STATS_LE32(ofdm, overrun_err); + PRINT_STATS_LE32(ofdm, early_overrun_err); + PRINT_STATS_LE32(ofdm, crc32_good); + PRINT_STATS_LE32(ofdm, false_alarm_cnt); + PRINT_STATS_LE32(ofdm, fina_sync_err_cnt); + PRINT_STATS_LE32(ofdm, sfd_timeout); + PRINT_STATS_LE32(ofdm, fina_timeout); + PRINT_STATS_LE32(ofdm, unresponded_rts); + PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(ofdm, sent_ack_cnt); + PRINT_STATS_LE32(ofdm, sent_cts_cnt); + PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); + PRINT_STATS_LE32(ofdm, dsp_self_kill); + PRINT_STATS_LE32(ofdm, mh_format_err); + PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum); + PRINT_STATS_LE32(ofdm, reserved); + } else { + struct mvm_statistics_rx_phy *ofdm = &mvm->rx_stats.ofdm; + + PRINT_STATS_LE32(ofdm, unresponded_rts); + PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); + PRINT_STATS_LE32(ofdm, dsp_self_kill); + PRINT_STATS_LE32(ofdm, reserved); + } pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - CCK"); - PRINT_STATS_LE32(cck, ina_cnt); - PRINT_STATS_LE32(cck, fina_cnt); - PRINT_STATS_LE32(cck, plcp_err); - PRINT_STATS_LE32(cck, crc32_err); - PRINT_STATS_LE32(cck, overrun_err); - PRINT_STATS_LE32(cck, early_overrun_err); - PRINT_STATS_LE32(cck, crc32_good); - PRINT_STATS_LE32(cck, false_alarm_cnt); - PRINT_STATS_LE32(cck, fina_sync_err_cnt); - PRINT_STATS_LE32(cck, sfd_timeout); - PRINT_STATS_LE32(cck, fina_timeout); - PRINT_STATS_LE32(cck, unresponded_rts); - PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); - PRINT_STATS_LE32(cck, sent_ack_cnt); - PRINT_STATS_LE32(cck, sent_cts_cnt); - PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); - PRINT_STATS_LE32(cck, dsp_self_kill); - PRINT_STATS_LE32(cck, mh_format_err); - PRINT_STATS_LE32(cck, re_acq_main_rssi_sum); - PRINT_STATS_LE32(cck, reserved); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_phy_v2 *cck = &mvm->rx_stats_v3.cck; + + PRINT_STATS_LE32(cck, ina_cnt); + PRINT_STATS_LE32(cck, fina_cnt); + PRINT_STATS_LE32(cck, plcp_err); + PRINT_STATS_LE32(cck, crc32_err); + PRINT_STATS_LE32(cck, overrun_err); + PRINT_STATS_LE32(cck, early_overrun_err); + PRINT_STATS_LE32(cck, crc32_good); + PRINT_STATS_LE32(cck, false_alarm_cnt); + PRINT_STATS_LE32(cck, fina_sync_err_cnt); + PRINT_STATS_LE32(cck, sfd_timeout); + PRINT_STATS_LE32(cck, fina_timeout); + PRINT_STATS_LE32(cck, unresponded_rts); + PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(cck, sent_ack_cnt); + PRINT_STATS_LE32(cck, sent_cts_cnt); + PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); + PRINT_STATS_LE32(cck, dsp_self_kill); + PRINT_STATS_LE32(cck, mh_format_err); + PRINT_STATS_LE32(cck, re_acq_main_rssi_sum); + PRINT_STATS_LE32(cck, reserved); + } else { + struct mvm_statistics_rx_phy *cck = &mvm->rx_stats.cck; + + PRINT_STATS_LE32(cck, unresponded_rts); + PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); + PRINT_STATS_LE32(cck, dsp_self_kill); + PRINT_STATS_LE32(cck, reserved); + } pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - GENERAL"); - PRINT_STATS_LE32(general, bogus_cts); - PRINT_STATS_LE32(general, bogus_ack); - PRINT_STATS_LE32(general, non_bssid_frames); - PRINT_STATS_LE32(general, filtered_frames); - PRINT_STATS_LE32(general, non_channel_beacons); - PRINT_STATS_LE32(general, channel_beacons); - PRINT_STATS_LE32(general, num_missed_bcon); - PRINT_STATS_LE32(general, adc_rx_saturation_time); - PRINT_STATS_LE32(general, ina_detection_search_time); - PRINT_STATS_LE32(general, beacon_silence_rssi_a); - PRINT_STATS_LE32(general, beacon_silence_rssi_b); - PRINT_STATS_LE32(general, beacon_silence_rssi_c); - PRINT_STATS_LE32(general, interference_data_flag); - PRINT_STATS_LE32(general, channel_load); - PRINT_STATS_LE32(general, dsp_false_alarms); - PRINT_STATS_LE32(general, beacon_rssi_a); - PRINT_STATS_LE32(general, beacon_rssi_b); - PRINT_STATS_LE32(general, beacon_rssi_c); - PRINT_STATS_LE32(general, beacon_energy_a); - PRINT_STATS_LE32(general, beacon_energy_b); - PRINT_STATS_LE32(general, beacon_energy_c); - PRINT_STATS_LE32(general, num_bt_kills); - PRINT_STATS_LE32(general, mac_id); - PRINT_STATS_LE32(general, directed_data_mpdu); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_non_phy_v3 *general = + &mvm->rx_stats_v3.general; + + PRINT_STATS_LE32(general, bogus_cts); + PRINT_STATS_LE32(general, bogus_ack); + PRINT_STATS_LE32(general, non_bssid_frames); + PRINT_STATS_LE32(general, filtered_frames); + PRINT_STATS_LE32(general, non_channel_beacons); + PRINT_STATS_LE32(general, channel_beacons); + PRINT_STATS_LE32(general, num_missed_bcon); + PRINT_STATS_LE32(general, adc_rx_saturation_time); + PRINT_STATS_LE32(general, ina_detection_search_time); + PRINT_STATS_LE32(general, beacon_silence_rssi_a); + PRINT_STATS_LE32(general, beacon_silence_rssi_b); + PRINT_STATS_LE32(general, beacon_silence_rssi_c); + PRINT_STATS_LE32(general, interference_data_flag); + PRINT_STATS_LE32(general, channel_load); + PRINT_STATS_LE32(general, dsp_false_alarms); + PRINT_STATS_LE32(general, beacon_rssi_a); + PRINT_STATS_LE32(general, beacon_rssi_b); + PRINT_STATS_LE32(general, beacon_rssi_c); + PRINT_STATS_LE32(general, beacon_energy_a); + PRINT_STATS_LE32(general, beacon_energy_b); + PRINT_STATS_LE32(general, beacon_energy_c); + PRINT_STATS_LE32(general, num_bt_kills); + PRINT_STATS_LE32(general, mac_id); + PRINT_STATS_LE32(general, directed_data_mpdu); + } else { + struct mvm_statistics_rx_non_phy *general = + &mvm->rx_stats.general; + + PRINT_STATS_LE32(general, bogus_cts); + PRINT_STATS_LE32(general, bogus_ack); + PRINT_STATS_LE32(general, non_channel_beacons); + PRINT_STATS_LE32(general, channel_beacons); + PRINT_STATS_LE32(general, num_missed_bcon); + PRINT_STATS_LE32(general, adc_rx_saturation_time); + PRINT_STATS_LE32(general, ina_detection_search_time); + PRINT_STATS_LE32(general, beacon_silence_rssi_a); + PRINT_STATS_LE32(general, beacon_silence_rssi_b); + PRINT_STATS_LE32(general, beacon_silence_rssi_c); + PRINT_STATS_LE32(general, interference_data_flag); + PRINT_STATS_LE32(general, channel_load); + PRINT_STATS_LE32(general, beacon_rssi_a); + PRINT_STATS_LE32(general, beacon_rssi_b); + PRINT_STATS_LE32(general, beacon_rssi_c); + PRINT_STATS_LE32(general, beacon_energy_a); + PRINT_STATS_LE32(general, beacon_energy_b); + PRINT_STATS_LE32(general, beacon_energy_c); + PRINT_STATS_LE32(general, num_bt_kills); + PRINT_STATS_LE32(general, mac_id); + } pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - HT"); - PRINT_STATS_LE32(ht, plcp_err); - PRINT_STATS_LE32(ht, overrun_err); - PRINT_STATS_LE32(ht, early_overrun_err); - PRINT_STATS_LE32(ht, crc32_good); - PRINT_STATS_LE32(ht, crc32_err); - PRINT_STATS_LE32(ht, mh_format_err); - PRINT_STATS_LE32(ht, agg_crc32_good); - PRINT_STATS_LE32(ht, agg_mpdu_cnt); - PRINT_STATS_LE32(ht, agg_cnt); - PRINT_STATS_LE32(ht, unsupport_mcs); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_ht_phy_v1 *ht = + &mvm->rx_stats_v3.ofdm_ht; + + PRINT_STATS_LE32(ht, plcp_err); + PRINT_STATS_LE32(ht, overrun_err); + PRINT_STATS_LE32(ht, early_overrun_err); + PRINT_STATS_LE32(ht, crc32_good); + PRINT_STATS_LE32(ht, crc32_err); + PRINT_STATS_LE32(ht, mh_format_err); + PRINT_STATS_LE32(ht, agg_crc32_good); + PRINT_STATS_LE32(ht, agg_mpdu_cnt); + PRINT_STATS_LE32(ht, agg_cnt); + PRINT_STATS_LE32(ht, unsupport_mcs); + } else { + struct mvm_statistics_rx_ht_phy *ht = + &mvm->rx_stats.ofdm_ht; + + PRINT_STATS_LE32(ht, mh_format_err); + PRINT_STATS_LE32(ht, agg_mpdu_cnt); + PRINT_STATS_LE32(ht, agg_cnt); + PRINT_STATS_LE32(ht, unsupport_mcs); + } mutex_unlock(&mvm->mutex); @@ -800,11 +924,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, { int __maybe_unused ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + mutex_lock(&mvm->mutex); /* allow one more restart that we're provoking here */ - if (mvm->restart_fw >= 0) - mvm->restart_fw++; + if (mvm->fw_restart >= 0) + mvm->fw_restart++; /* take the return value to make compiler happy - it will fail anyway */ ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL); @@ -817,7 +944,12 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); + int ret; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); if (ret) return ret; @@ -857,6 +989,9 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, { u8 scan_rx_ant; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) return -EINVAL; if (scan_rx_ant > ANT_ABC) @@ -911,7 +1046,11 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm, netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key)); mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); + if (iwl_mvm_firmware_running(mvm)) + ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, + sizeof(cmd), &cmd); + else + ret = 0; mutex_unlock(&mvm->mutex); return ret ?: count; @@ -931,6 +1070,9 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, int bin_len = count / 2; int ret = -EINVAL; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + /* supporting only 9000 descriptor */ if (!mvm->trans->cfg->mq_rx_supported) return -ENOTSUPP; @@ -1004,11 +1146,14 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm, struct iwl_continuous_record_cmd cont_rec = {}; int ret, rec_mode; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + if (!dest) return -EOPNOTSUPP; if (dest->monitor_mode != SMEM_MODE || - trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) return -EOPNOTSUPP; ret = kstrtoint(buf, 0, &rec_mode); @@ -1034,6 +1179,9 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, unsigned int conf_id; int ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + ret = kstrtouint(buf, 0, &conf_id); if (ret) return ret; @@ -1052,8 +1200,12 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); + int ret; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); if (ret) return ret; if (count == 0) @@ -1184,7 +1336,8 @@ static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf, &filter, sizeof(filter)); /* send updated bcast filtering configuration */ - if (mvm->dbgfs_bcast_filtering.override && + if (iwl_mvm_firmware_running(mvm) && + mvm->dbgfs_bcast_filtering.override && iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, sizeof(cmd), &cmd); @@ -1256,7 +1409,8 @@ static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, &mac, sizeof(mac)); /* send updated bcast filtering configuration */ - if (mvm->dbgfs_bcast_filtering.override && + if (iwl_mvm_firmware_running(mvm) && + mvm->dbgfs_bcast_filtering.override && iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, sizeof(cmd), &cmd); @@ -1473,6 +1627,9 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, { int ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + mutex_lock(&mvm->mutex); ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL); mutex_unlock(&mvm->mutex); @@ -1519,6 +1676,9 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); #endif +#ifdef CONFIG_ACPI +MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); +#endif static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1534,6 +1694,9 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, size_t delta; ssize_t ret, len; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR, DEBUG_GROUP, 0); cmd.op = cpu_to_le32(DEBUG_MEM_OP_READ); @@ -1586,6 +1749,9 @@ static ssize_t iwl_dbgfs_mem_write(struct file *file, u32 op, len; ssize_t ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR, DEBUG_GROUP, 0); @@ -1685,6 +1851,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR); +#ifdef CONFIG_ACPI + MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, S_IRUSR); +#endif + if (!debugfs_create_bool("enable_scan_iteration_notif", S_IRUSR | S_IWUSR, mvm->debugfs_dir, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h index 204c1b13988b..8cd06aaa1f54 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h @@ -7,6 +7,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2017 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 @@ -33,6 +34,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -99,8 +101,8 @@ enum iwl_bt_coex_enabled_modules { /** * struct iwl_bt_coex_cmd - bt coex configuration command - * @mode: enum %iwl_bt_coex_mode - * @enabled_modules: enum %iwl_bt_coex_enabled_modules + * @mode: &enum iwl_bt_coex_mode + * @enabled_modules: &enum iwl_bt_coex_enabled_modules * * The structure is used for the BT_COEX command. */ @@ -132,10 +134,10 @@ struct iwl_bt_coex_reduced_txp_update_cmd { /** * struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command - * @bt_primary_ci: - * @primary_ch_phy_id: - * @bt_secondary_ci: - * @secondary_ch_phy_id: + * @bt_primary_ci: primary channel inhibition bitmap + * @primary_ch_phy_id: primary channel PHY ID + * @bt_secondary_ci: secondary channel inhibition bitmap + * @secondary_ch_phy_id: secondary channel PHY ID * * Used for BT_COEX_CI command */ @@ -234,10 +236,11 @@ enum iwl_bt_ci_compliance { * @mbox_msg: message from BT to WiFi * @msg_idx: the index of the message * @bt_ci_compliance: enum %iwl_bt_ci_compliance - * @primary_ch_lut: LUT used for primary channel enum %iwl_bt_coex_lut_type - * @secondary_ch_lut: LUT used for secondary channel enume %iwl_bt_coex_lut_type - * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading + * @primary_ch_lut: LUT used for primary channel &enum iwl_bt_coex_lut_type + * @secondary_ch_lut: LUT used for secondary channel &enum iwl_bt_coex_lut_type + * @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading * @ttc_rrc_status: is TTC or RRC enabled - one bit per PHY + * @reserved: reserved */ struct iwl_bt_coex_profile_notif { __le32 mbox_msg[4]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h index 5f22cc7ac26a..d4a4c28b7192 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 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 @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -138,6 +139,7 @@ struct iwl_proto_offload_cmd_common { * for each target address * @target_ipv6_addr: our target addresses * @ndp_mac_addr: neighbor solicitation response MAC address + * @reserved2: reserved */ struct iwl_proto_offload_cmd_v1 { struct iwl_proto_offload_cmd_common common; @@ -156,6 +158,8 @@ struct iwl_proto_offload_cmd_v1 { * for each target address * @target_ipv6_addr: our target addresses * @ndp_mac_addr: neighbor solicitation response MAC address + * @num_valid_ipv6_addrs: number of valid IPv6 addresses + * @reserved2: reserved */ struct iwl_proto_offload_cmd_v2 { struct iwl_proto_offload_cmd_common common; @@ -163,7 +167,7 @@ struct iwl_proto_offload_cmd_v2 { u8 solicited_node_ipv6_addr[16]; u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2][16]; u8 ndp_mac_addr[ETH_ALEN]; - u8 numValidIPv6Addresses; + u8 num_valid_ipv6_addrs; u8 reserved2[3]; } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ @@ -182,7 +186,8 @@ struct iwl_targ_addr { /** * struct iwl_proto_offload_cmd_v3_small - ARP/NS offload configuration * @common: common/IPv4 configuration - * @target_ipv6_addr: target IPv6 addresses + * @num_valid_ipv6_addrs: number of valid IPv6 addresses + * @targ_addrs: target IPv6 addresses * @ns_config: NS offload configurations */ struct iwl_proto_offload_cmd_v3_small { @@ -195,7 +200,8 @@ struct iwl_proto_offload_cmd_v3_small { /** * struct iwl_proto_offload_cmd_v3_large - ARP/NS offload configuration * @common: common/IPv4 configuration - * @target_ipv6_addr: target IPv6 addresses + * @num_valid_ipv6_addrs: number of valid IPv6 addresses + * @targ_addrs: target IPv6 addresses * @ns_config: NS offload configurations */ struct iwl_proto_offload_cmd_v3_large { @@ -254,6 +260,17 @@ enum iwl_wowlan_flags { ENABLE_STORE_BEACON = BIT(4), }; +/** + * struct iwl_wowlan_config_cmd - WoWLAN configuration + * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters + * @non_qos_seq: non-QoS sequence counter to use next + * @qos_seq: QoS sequence counters to use next + * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down + * @is_11n_connection: indicates HT connection + * @offloading_tid: TID reserved for firmware use + * @flags: extra flags, see &enum iwl_wowlan_flags + * @reserved: reserved + */ struct iwl_wowlan_config_cmd { __le32 wakeup_filter; __le16 non_qos_seq; @@ -370,6 +387,21 @@ struct iwl_wowlan_gtk_status { struct iwl_wowlan_rsc_tsc_params_cmd rsc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */ +/** + * struct iwl_wowlan_status - WoWLAN status + * @gtk: GTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched pattern + * @non_qos_seq_ctr: non-QoS sequence counter to use next + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @wake_packet_length: wakeup packet length + * @wake_packet_bufsize: wakeup packet buffer size + * @wake_packet: wakeup packet + */ struct iwl_wowlan_status { struct iwl_wowlan_gtk_status gtk; __le64 replay_ctr; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index 970b030ed28d..0c3350ad2f2f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -199,6 +199,7 @@ struct iwl_mac_data_ibss { * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated * @listen_interval: in beacon intervals, applicable only when associated * @assoc_id: unique ID assigned by the AP during association + * @assoc_beacon_arrive_time: TSF of first beacon after association */ struct iwl_mac_data_sta { __le32 is_assoc; @@ -329,19 +330,20 @@ struct iwl_ac_qos { * ( MAC_CONTEXT_CMD = 0x28 ) * @id_and_color: ID and color of the MAC * @action: action to perform, one of FW_CTXT_ACTION_* - * @mac_type: one of FW_MAC_TYPE_* - * @tsd_id: TSF HW timer, one of TSF_ID_* + * @mac_type: one of &enum iwl_mac_types + * @tsf_id: TSF HW timer, one of &enum iwl_tsf_id * @node_addr: MAC address + * @reserved_for_node_addr: reserved * @bssid_addr: BSSID + * @reserved_for_bssid_addr: reserved * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM - * @protection_flags: combination of MAC_PROT_FLG_FLAG_* + * @protection_flags: combination of &enum iwl_mac_protection_flags * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise * @short_slot: 0x10 for enabling short slots, 0 otherwise - * @filter_flags: combination of MAC_FILTER_* - * @qos_flags: from MAC_QOS_FLG_* + * @filter_flags: combination of &enum iwl_mac_filter_flags + * @qos_flags: from &enum iwl_mac_qos_flags * @ac: one iwl_mac_qos configuration for each AC - * @mac_specific: one of struct iwl_mac_data_*, according to mac_type */ struct iwl_mac_ctx_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index 750510aff70b..7da57ef2454e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -82,6 +82,8 @@ * @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register * @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register * @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD + * @LTR_CFG_FLAG_UPDATE_VALUES: update config values and short + * idle timeout */ enum iwl_ltr_config_flags { LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0), @@ -91,11 +93,14 @@ enum iwl_ltr_config_flags { LTR_CFG_FLAG_SW_SET_SHORT = BIT(4), LTR_CFG_FLAG_SW_SET_LONG = BIT(5), LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6), + LTR_CFG_FLAG_UPDATE_VALUES = BIT(7), }; /** * struct iwl_ltr_config_cmd_v1 - configures the LTR - * @flags: See %enum iwl_ltr_config_flags + * @flags: See &enum iwl_ltr_config_flags + * @static_long: static LTR Long register value. + * @static_short: static LTR Short register value. */ struct iwl_ltr_config_cmd_v1 { __le32 flags; @@ -107,11 +112,14 @@ struct iwl_ltr_config_cmd_v1 { /** * struct iwl_ltr_config_cmd - configures the LTR - * @flags: See %enum iwl_ltr_config_flags - * @static_long: - * @static_short: - * @ltr_cfg_values: - * @ltr_short_idle_timeout: + * @flags: See &enum iwl_ltr_config_flags + * @static_long: static LTR Long register value. + * @static_short: static LTR Short register value. + * @ltr_cfg_values: LTR parameters table values (in usec) in folowing order: + * TX, RX, Short Idle, Long Idle. Used only if %LTR_CFG_FLAG_UPDATE_VALUES + * is set. + * @ltr_short_idle_timeout: LTR Short Idle timeout (in usec). Used only if + * %LTR_CFG_FLAG_UPDATE_VALUES is set. */ struct iwl_ltr_config_cmd { __le32 flags; @@ -140,7 +148,7 @@ struct iwl_ltr_config_cmd { * PBW Snoozing enabled * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. - * @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving + * @POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving * detection enablement */ enum iwl_power_flags { @@ -166,6 +174,7 @@ enum iwl_power_flags { * Minimum allowed:- 3 * DTIM. Keep alive period must be * set regardless of power scheme or current power state. * FW use this value also when PM is disabled. + * @debug_flags: debug flags * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to @@ -191,7 +200,8 @@ struct iwl_powertable_cmd { /** * enum iwl_device_power_flags - masks for device power command flags - * @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off + * @DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK: + * '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. */ enum iwl_device_power_flags { @@ -202,7 +212,8 @@ enum iwl_device_power_flags { * struct iwl_device_power_cmd - device wide power command. * DEVICE_POWER_CMD = 0x77 (command, has simple generic response) * - * @flags: Power table command flags from DEVICE_POWER_FLAGS_* + * @flags: Power table command flags from &enum iwl_device_power_flags + * @reserved: reserved (padding) */ struct iwl_device_power_cmd { /* PM_POWER_TABLE_CMD_API_S_VER_6 */ @@ -213,7 +224,7 @@ struct iwl_device_power_cmd { /** * struct iwl_mac_power_cmd - New power command containing uAPSD support * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) - * @id_and_color: MAC contex identifier + * @id_and_color: MAC contex identifier, &enum iwl_mvm_id_and_color * @flags: Power table command flags from POWER_FLAGS_* * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * Minimum allowed:- 3 * DTIM. Keep alive period must be @@ -223,7 +234,6 @@ struct iwl_device_power_cmd { * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to * PSM transition - legacy PM - * @sleep_interval: not in use * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag * is set. For example, if it is required to skip over * one DTIM, this value need to be set to 2 (DTIM periods). @@ -233,7 +243,6 @@ struct iwl_device_power_cmd { * PSM transition - uAPSD * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * Default: 80dbm - * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set * @snooze_interval: Maximum time between attempts to retrieve buffered data * from the AP [msec] * @snooze_window: A window of time in which PBW snoozing insures that all @@ -251,8 +260,9 @@ struct iwl_device_power_cmd { * @heavy_rx_thld_packets: RX threshold measured in number of packets * @heavy_tx_thld_percentage: TX threshold measured in load's percentage * @heavy_rx_thld_percentage: RX threshold measured in load's percentage - * @limited_ps_threshold: -*/ + * @limited_ps_threshold: (unused) + * @reserved: reserved (padding) + */ struct iwl_mac_power_cmd { /* CONTEXT_DESC_API_T_VER_1 */ __le32 id_and_color; @@ -343,6 +353,7 @@ struct iwl_dev_tx_power_cmd_v3 { * @v3: version 3 of the command, embedded here for easier software handling * @enable_ack_reduction: enable or disable close range ack TX power * reduction. + * @reserved: reserved (padding) */ struct iwl_dev_tx_power_cmd { /* v4 is just an extension of v3 - keep this here */ @@ -352,6 +363,7 @@ struct iwl_dev_tx_power_cmd { } __packed; /* TX_REDUCED_POWER_API_S_VER_4 */ #define IWL_NUM_GEO_PROFILES 3 +#define IWL_GEO_PER_CHAIN_SIZE 3 /** * enum iwl_geo_per_chain_offset_operation - type of operation @@ -391,9 +403,16 @@ struct iwl_geo_tx_power_profiles_cmd { } __packed; /* GEO_TX_POWER_LIMIT */ /** + * struct iwl_geo_tx_power_profiles_resp - response to GEO_TX_POWER_LIMIT cmd + * @profile_idx: current geo profile in use + */ +struct iwl_geo_tx_power_profiles_resp { + __le32 profile_idx; +} __packed; /* GEO_TX_POWER_LIMIT_RESP */ + +/** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) - * @id_and_color: MAC contex identifier * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon * to driver if delta in Energy values calculated for this and last * passed beacon is greater than this threshold. Zero value means that @@ -411,7 +430,7 @@ struct iwl_geo_tx_power_profiles_cmd { * Threshold. Typical energy threshold is -72dBm. * @bf_temp_threshold: This threshold determines the type of temperature * filtering (Slow or Fast) that is selected (Units are in Celsuis): - * If the current temperature is above this threshold - Fast filter + * If the current temperature is above this threshold - Fast filter * will be used, If the current temperature is below this threshold - * Slow filter will be used. * @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values @@ -425,7 +444,8 @@ struct iwl_geo_tx_power_profiles_cmd { * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temerature has been changed. * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. - * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed + * @bf_debug_flag: beacon filtering debug configuration + * @bf_escape_timer: Send beacons to to driver if no beacons were passed * for a specific period of time. Units: Beacons. * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed * for a longer period of time then this escape-timeout. Units: Beacons. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h index a10c6aae9ab9..bdf1228d050b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h @@ -368,6 +368,7 @@ enum { /** * struct iwl_lq_cmd - link quality command * @sta_id: station to update + * @reduced_tpc: reduced transmit power control value * @control: not used * @flags: combination of LQ_FLAG_* * @mimo_delim: the first SISO index in rs_table, which separates MIMO @@ -385,6 +386,7 @@ enum { * 0: no limit * 1: no aggregation (one frame per aggregation) * 2 - 0x3f: maximal number of frames (up to 3f == 63) + * @reserved2: reserved * @rs_table: array of rates for each TX try, each is rate_n_flags, * meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP * @ss_params: single stream features. declare whether STBC or BFER are allowed. @@ -392,7 +394,7 @@ enum { struct iwl_lq_cmd { u8 sta_id; u8 reduced_tpc; - u16 control; + __le16 control; /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */ u8 flags; u8 mimo_delim; @@ -407,4 +409,5 @@ struct iwl_lq_cmd { __le32 rs_table[LQ_MAX_RETRY_NUM]; __le32 ss_params; }; /* LINK_QUALITY_CMD_API_S_VER_1 */ + #endif /* __fw_api_rs_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index b530fa47d68a..59038ade08d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 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 @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -90,13 +90,13 @@ enum iwl_mac_context_info { * @non_cfg_phy_cnt: non configurable DSP phy data byte count * @cfg_phy_cnt: configurable DSP phy data byte count * @stat_id: configurable DSP phy data set ID - * @reserved1: + * @reserved1: reserved * @system_timestamp: GP2 at on air rise * @timestamp: TSF at on air rise * @beacon_time_stamp: beacon at on-air rise * @phy_flags: general phy flags: band, modulation, ... * @channel: channel number - * @non_cfg_phy_buf: for various implementations of non_cfg_phy + * @non_cfg_phy: for various implementations of non_cfg_phy * @rate_n_flags: RATE_MCS_* * @byte_count: frame's byte-count * @frame_time: frame's time on the air, based on byte count and frame rate @@ -147,7 +147,8 @@ enum iwl_csum_rx_assist_info { /** * struct iwl_rx_mpdu_res_start - phy info - * @assist: see CSUM_RX_ASSIST_ above + * @byte_count: byte count of the frame + * @assist: see &enum iwl_csum_rx_assist_info */ struct iwl_rx_mpdu_res_start { __le16 byte_count; @@ -157,10 +158,11 @@ struct iwl_rx_mpdu_res_start { /** * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags * @RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band - * @RX_RES_PHY_FLAGS_MOD_CCK: + * @RX_RES_PHY_FLAGS_MOD_CCK: modulation is CCK * @RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short - * @RX_RES_PHY_FLAGS_NARROW_BAND: + * @RX_RES_PHY_FLAGS_NARROW_BAND: narrow band (<20 MHz) receive * @RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received + * @RX_RES_PHY_FLAGS_ANTENNA_POS: antenna bit position * @RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU * @RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame * @RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble @@ -183,9 +185,9 @@ enum iwl_rx_phy_flags { * enum iwl_mvm_rx_status - written by fw for each Rx packet * @RX_MPDU_RES_STATUS_CRC_OK: CRC is fine * @RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow - * @RX_MPDU_RES_STATUS_SRC_STA_FOUND: - * @RX_MPDU_RES_STATUS_KEY_VALID: - * @RX_MPDU_RES_STATUS_KEY_PARAM_OK: + * @RX_MPDU_RES_STATUS_SRC_STA_FOUND: station was found + * @RX_MPDU_RES_STATUS_KEY_VALID: key was valid + * @RX_MPDU_RES_STATUS_KEY_PARAM_OK: key parameters were usable * @RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed * @RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked * in the driver. @@ -197,21 +199,21 @@ enum iwl_rx_phy_flags { * @RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP * @RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM * @RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP + * @RX_MPDU_RES_STATUS_SEC_EXT_ENC: this frame is encrypted using extension + * algorithm * @RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC * @RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted - * @RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP: - * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: - * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: + * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: extended IV (set with TKIP) + * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: key ID comparison done * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame * @RX_MPDU_RES_STATUS_CSUM_DONE: checksum was done by the hw * @RX_MPDU_RES_STATUS_CSUM_OK: checksum found no errors - * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK: - * @RX_MPDU_RES_STATUS_STA_ID_MSK: - * @RX_MPDU_RES_STATUS_RRF_KILL: - * @RX_MPDU_RES_STATUS_FILTERING_MSK: - * @RX_MPDU_RES_STATUS2_FILTERING_MSK: + * @RX_MPDU_RES_STATUS_STA_ID_MSK: station ID mask + * @RX_MDPU_RES_STATUS_STA_ID_SHIFT: station ID bit shift + * @RX_MPDU_RES_STATUS_FILTERING_MSK: filter status + * @RX_MPDU_RES_STATUS2_FILTERING_MSK: filter status 2 */ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_CRC_OK = BIT(0), @@ -232,16 +234,13 @@ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8), RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), RX_MPDU_RES_STATUS_DEC_DONE = BIT(11), - RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP = BIT(12), RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = BIT(13), RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = BIT(14), RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = BIT(15), RX_MPDU_RES_STATUS_CSUM_DONE = BIT(16), RX_MPDU_RES_STATUS_CSUM_OK = BIT(17), - RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000), RX_MDPU_RES_STATUS_STA_ID_SHIFT = 24, RX_MPDU_RES_STATUS_STA_ID_MSK = 0x1f << RX_MDPU_RES_STATUS_STA_ID_SHIFT, - RX_MPDU_RES_STATUS_RRF_KILL = BIT(29), RX_MPDU_RES_STATUS_FILTERING_MSK = (0xc00000), RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000), }; @@ -348,35 +347,106 @@ enum iwl_rx_mpdu_mac_info { IWL_RX_MPDU_PHY_PHY_INDEX_MASK = 0xf0, }; +/** + * struct iwl_rx_mpdu_desc - RX MPDU descriptor + */ struct iwl_rx_mpdu_desc { /* DW2 */ + /** + * @mpdu_len: MPDU length + */ __le16 mpdu_len; + /** + * @mac_flags1: &enum iwl_rx_mpdu_mac_flags1 + */ u8 mac_flags1; + /** + * @mac_flags2: &enum iwl_rx_mpdu_mac_flags2 + */ u8 mac_flags2; /* DW3 */ + /** + * @amsdu_info: &enum iwl_rx_mpdu_amsdu_info + */ u8 amsdu_info; + /** + * @phy_info: &enum iwl_rx_mpdu_phy_info + */ __le16 phy_info; + /** + * @mac_phy_idx: MAC/PHY index + */ u8 mac_phy_idx; /* DW4 - carries csum data only when rpa_en == 1 */ - __le16 raw_csum; /* alledgedly unreliable */ + /** + * @raw_csum: raw checksum (alledgedly unreliable) + */ + __le16 raw_csum; + /** + * @l3l4_flags: &enum iwl_rx_l3l4_flags + */ __le16 l3l4_flags; /* DW5 */ + /** + * @status: &enum iwl_rx_mpdu_status + */ __le16 status; + /** + * @hash_filter: hash filter value + */ u8 hash_filter; + /** + * @sta_id_flags: &enum iwl_rx_mpdu_sta_id_flags + */ u8 sta_id_flags; /* DW6 */ + /** + * @reorder_data: &enum iwl_rx_mpdu_reorder_data + */ __le32 reorder_data; /* DW7 - carries rss_hash only when rpa_en == 1 */ + /** + * @rss_hash: RSS hash value + */ __le32 rss_hash; /* DW8 - carries filter_match only when rpa_en == 1 */ + /** + * @filter_match: filter match value + */ __le32 filter_match; /* DW9 */ + /** + * @rate_n_flags: RX rate/flags encoding + */ __le32 rate_n_flags; /* DW10 */ - u8 energy_a, energy_b, channel, mac_context; + /** + * @energy_a: energy chain A + */ + u8 energy_a; + /** + * @energy_b: energy chain B + */ + u8 energy_b; + /** + * @channel: channel number + */ + u8 channel; + /** + * @mac_context: MAC context mask + */ + u8 mac_context; /* DW11 */ + /** + * @gp2_on_air_rise: GP2 timer value on air rise (INA) + */ __le32 gp2_on_air_rise; - /* DW12 & DW13 - carries TSF only TSF_OVERLOAD bit == 0 */ + /* DW12 & DW13 */ + /** + * @tsf_on_air_rise: + * TSF value on air rise (INA), only valid if + * %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set + */ __le64 tsf_on_air_rise; } __packed; @@ -404,6 +474,7 @@ enum iwl_rss_hash_func_en { * * @flags: 1 - enable, 0 - disable * @hash_mask: Type of RSS to use. Values are from %iwl_rss_hash_func_en + * @reserved: reserved * @secret_key: 320 bit input of random key configuration from driver * @indirection_table: indirection table */ @@ -447,7 +518,7 @@ struct iwl_rxq_sync_notification { } __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */ /** - * Internal message identifier + * enum iwl_mvm_rxq_notif_type - Internal message identifier * * @IWL_MVM_RXQ_EMPTY: empty sync notification * @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA @@ -491,13 +562,13 @@ enum iwl_mvm_pm_event { /** * struct iwl_mvm_pm_state_notification - station PM state notification * @sta_id: station ID of the station changing state - * @type: the new powersave state, see IWL_MVM_PM_EVENT_ above + * @type: the new powersave state, see &enum iwl_mvm_pm_event */ struct iwl_mvm_pm_state_notification { u8 sta_id; u8 type; /* private: */ - u16 reserved; + __le16 reserved; } __packed; /* PEER_PM_NTFY_API_S_VER_1 */ #endif /* __fw_api_rx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index 3178eb96e395..1cd7cc087936 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 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 @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,8 +68,6 @@ #ifndef __fw_api_scan_h__ #define __fw_api_scan_h__ -#include "fw-api.h" - /* Scan Commands, Responses, Notifications */ /* Max number of IEs for direct SSID scans in a command */ @@ -81,6 +80,10 @@ * selected by "type" bit field in struct iwl_scan_channel; * each channel may select different ssids from among the 20 entries. * SSID IEs get transmitted in reverse order of entry. + * + * @id: element ID + * @len: element length + * @ssid: element (SSID) data */ struct iwl_ssid_ie { u8 id; @@ -111,7 +114,7 @@ enum scan_framework_client { }; /** - * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S + * struct iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S * @ssid: MAC address to filter out * @reported_rssi: AP rssi reported to the host * @client_bitmap: clients ignore this entry - enum scan_framework_client @@ -135,13 +138,14 @@ enum iwl_scan_offload_band_selection { }; /** - * iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S + * struct iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S * @ssid_index: index to ssid list in fixed part * @unicast_cipher: encryption algorithm to match - bitmap - * @aut_alg: authentication algorithm to match - bitmap + * @auth_alg: authentication algorithm to match - bitmap * @network_type: enum iwl_scan_offload_network_type * @band_selection: enum iwl_scan_offload_band_selection * @client_bitmap: clients waiting for match - enum scan_framework_client + * @reserved: reserved */ struct iwl_scan_offload_profile { u8 ssid_index; @@ -154,8 +158,7 @@ struct iwl_scan_offload_profile { } __packed; /** - * iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 - * @blaclist: AP list to filter off from scan results + * struct iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 * @profiles: profiles to search for match * @blacklist_len: length of blacklist * @num_profiles: num of profiles in the list @@ -163,6 +166,7 @@ struct iwl_scan_offload_profile { * @pass_match: clients waiting for the results * @active_clients: active clients bitmap - enum scan_framework_client * @any_beacon_notify: clients waiting for match notification without match + * @reserved: reserved */ struct iwl_scan_offload_profile_cfg { struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; @@ -176,7 +180,7 @@ struct iwl_scan_offload_profile_cfg { } __packed; /** - * iwl_scan_schedule_lmac - schedule of scan offload + * struct iwl_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 @@ -200,7 +204,7 @@ enum iwl_scan_ebs_status { }; /** - * iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S + * struct iwl_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_* @@ -220,10 +224,10 @@ enum iwl_scan_channel_flags_lmac { }; /** - * iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 + * struct iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 * @flags: bits 1-20: directed scan to i'th ssid * other bits &enum iwl_scan_channel_flags_lmac - * @channel_number: channel number 1-13 etc + * @channel_num: channel number 1-13 etc * @iter_count: scan iteration on this channel * @iter_interval: interval in seconds between iterations on one channel */ @@ -235,7 +239,7 @@ struct iwl_scan_channel_cfg_lmac { } __packed; /* - * iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 + * struct iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 * @offset: offset in the data block * @len: length of the segment */ @@ -263,7 +267,7 @@ enum iwl_scan_channel_flags { IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2), }; -/* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S +/* struct iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S * @flags: enum iwl_scan_channel_flags * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is * involved. @@ -276,13 +280,13 @@ struct iwl_scan_channel_opt { } __packed; /** - * iwl_mvm_lmac_scan_flags + * enum iwl_mvm_lmac_scan_flags - LMAC scan flags * @IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses * without filtering. * @IWL_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels * @IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION: single channel scan * @IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification - * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching + * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS: multiple SSID matching * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report * and DS parameter set IEs into probe requests. @@ -320,15 +324,15 @@ enum iwl_scan_priority_ext { }; /** - * iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1 + * struct iwl_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 + * @n_channels: 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 + * @rx_chain_select: PHY_RX_CHAIN_* flags * @scan_flags: &enum iwl_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 @@ -410,12 +414,13 @@ struct iwl_lmac_scan_complete_notif { } __packed; /** - * iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 + * struct iwl_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 iwl_scan_offload_complete_status + * @status: &enum iwl_scan_offload_complete_status * @ebs_status: EBS success status &enum iwl_scan_ebs_status - * @time_after_last_iter; time in seconds elapsed after last iteration + * @time_after_last_iter: time in seconds elapsed after last iteration + * @reserved: reserved */ struct iwl_periodic_scan_complete { u8 last_schedule_line; @@ -547,12 +552,12 @@ struct iwl_scan_config { } __packed; /* SCAN_CONFIG_DB_CMD_API_S_3 */ /** - * iwl_umac_scan_flags - *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request + * enum iwl_umac_scan_flags - UMAC scan flags + * @IWL_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. - *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver + * @IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver * when scan starts. */ enum iwl_umac_scan_flags { @@ -701,8 +706,8 @@ struct iwl_umac_scan_abort { * struct iwl_umac_scan_complete * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @last_schedule: last scheduling line - * @last_iter: last scan iteration number - * @scan status: &enum iwl_scan_offload_complete_status + * @last_iter: last scan iteration number + * @status: &enum iwl_scan_offload_complete_status * @ebs_status: &enum iwl_scan_ebs_status * @time_from_last_iter: time elapsed from last iteration * @reserved: for future use @@ -721,9 +726,10 @@ struct iwl_umac_scan_complete { /** * struct iwl_scan_offload_profile_match - match information * @bssid: matched bssid + * @reserved: reserved * @channel: channel where the match occurred - * @energy: - * @matching_feature: + * @energy: energy + * @matching_feature: feature matches * @matching_channels: bitmap of channels that matched, referencing * the channels passed in tue scan offload request */ @@ -771,7 +777,7 @@ struct iwl_scan_offload_profiles_query { * @last_channel: last channel that was scanned * @start_tsf: TSF timer in usecs of the scan start time for the mac specified * in &struct iwl_scan_req_umac. - * @results: array of scan results, only "scanned_channels" of them are valid + * @results: array of scan results, length in @scanned_channels */ struct iwl_umac_scan_iter_complete_notif { __le32 uid; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 421b9dd1fb66..81f0a3463bac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -69,8 +69,8 @@ /** * enum iwl_sta_flags - flags for the ADD_STA host command - * @STA_FLG_REDUCED_TX_PWR_CTRL: - * @STA_FLG_REDUCED_TX_PWR_DATA: + * @STA_FLG_REDUCED_TX_PWR_CTRL: reduced TX power (control frames) + * @STA_FLG_REDUCED_TX_PWR_DATA: reduced TX power (data frames) * @STA_FLG_DISABLE_TX: set if TX should be disabled * @STA_FLG_PS: set if STA is in Power Save * @STA_FLG_INVALID: set if STA is invalid @@ -78,18 +78,40 @@ * @STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs * @STA_FLG_DRAIN_FLOW: drain flow * @STA_FLG_PAN: STA is for PAN interface - * @STA_FLG_CLASS_AUTH: - * @STA_FLG_CLASS_ASSOC: - * @STA_FLG_CLASS_MIMO_PROT: - * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU + * @STA_FLG_CLASS_AUTH: station is authenticated + * @STA_FLG_CLASS_ASSOC: station is associated + * @STA_FLG_RTS_MIMO_PROT: station requires RTS MIMO protection (dynamic SMPS) + * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU (mask) + * @STA_FLG_MAX_AGG_SIZE_SHIFT: maximal size for A-MPDU (bit shift) + * @STA_FLG_MAX_AGG_SIZE_8K: maximal size for A-MPDU (8k supported) + * @STA_FLG_MAX_AGG_SIZE_16K: maximal size for A-MPDU (16k supported) + * @STA_FLG_MAX_AGG_SIZE_32K: maximal size for A-MPDU (32k supported) + * @STA_FLG_MAX_AGG_SIZE_64K: maximal size for A-MPDU (64k supported) + * @STA_FLG_MAX_AGG_SIZE_128K: maximal size for A-MPDU (128k supported) + * @STA_FLG_MAX_AGG_SIZE_256K: maximal size for A-MPDU (256k supported) + * @STA_FLG_MAX_AGG_SIZE_512K: maximal size for A-MPDU (512k supported) + * @STA_FLG_MAX_AGG_SIZE_1024K: maximal size for A-MPDU (1024k supported) * @STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation * @STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is * initialised by driver and can be updated by fw upon reception of * action frames that can change the channel width. When cleared the fw * will send all the frames in 20MHz even when FAT channel is requested. + * @STA_FLG_FAT_EN_20MHZ: no wide channels are supported, only 20 MHz + * @STA_FLG_FAT_EN_40MHZ: wide channels up to 40 MHz supported + * @STA_FLG_FAT_EN_80MHZ: wide channels up to 80 MHz supported + * @STA_FLG_FAT_EN_160MHZ: wide channels up to 160 MHz supported * @STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the * driver and can be updated by fw upon reception of action frames. + * @STA_FLG_MIMO_EN_SISO: no support for MIMO + * @STA_FLG_MIMO_EN_MIMO2: 2 streams supported + * @STA_FLG_MIMO_EN_MIMO3: 3 streams supported * @STA_FLG_MFP_EN: Management Frame Protection + * @STA_FLG_AGG_MPDU_DENS_MSK: A-MPDU density (mask) + * @STA_FLG_AGG_MPDU_DENS_SHIFT: A-MPDU density (bit shift) + * @STA_FLG_AGG_MPDU_DENS_2US: A-MPDU density (2 usec gap) + * @STA_FLG_AGG_MPDU_DENS_4US: A-MPDU density (4 usec gap) + * @STA_FLG_AGG_MPDU_DENS_8US: A-MPDU density (8 usec gap) + * @STA_FLG_AGG_MPDU_DENS_16US: A-MPDU density (16 usec gap) */ enum iwl_sta_flags { STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3), @@ -148,9 +170,10 @@ enum iwl_sta_flags { * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * station info array (1 - n 1X mode) * @STA_KEY_FLG_KEYID_MSK: the index of the key + * @STA_KEY_FLG_KEYID_POS: key index bit position * @STA_KEY_NOT_VALID: key is invalid * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key - * @STA_KEY_FLG_KEY_32BYTES for non-wep key set for 32 bytes key + * @STA_KEY_FLG_KEY_32BYTES: for non-wep key set for 32 bytes key * @STA_KEY_MULTICAST: set for multical key * @STA_KEY_MFP: key is used for Management Frame Protection */ @@ -183,7 +206,7 @@ enum iwl_sta_key_flag { * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count - * @STA_MODIFY_PROT_TH: + * @STA_MODIFY_PROT_TH: modify RTS threshold * @STA_MODIFY_QUEUES: modify the queues used by this station */ enum iwl_sta_modify_flag { @@ -197,13 +220,21 @@ enum iwl_sta_modify_flag { STA_MODIFY_QUEUES = BIT(7), }; -#define STA_MODE_MODIFY 1 +/** + * enum iwl_sta_mode - station command mode + * @STA_MODE_ADD: add new station + * @STA_MODE_MODIFY: modify the station + */ +enum iwl_sta_mode { + STA_MODE_ADD = 0, + STA_MODE_MODIFY = 1, +}; /** * enum iwl_sta_sleep_flag - type of sleep of the station - * @STA_SLEEP_STATE_AWAKE: - * @STA_SLEEP_STATE_PS_POLL: - * @STA_SLEEP_STATE_UAPSD: + * @STA_SLEEP_STATE_AWAKE: station is awake + * @STA_SLEEP_STATE_PS_POLL: station is PS-polling + * @STA_SLEEP_STATE_UAPSD: station uses U-APSD * @STA_SLEEP_STATE_MOREDATA: set more-data bit on * (last) released frame */ @@ -223,10 +254,12 @@ enum iwl_sta_sleep_flag { /** * struct iwl_mvm_keyinfo - key information - * @key_flags: type %iwl_sta_key_flag + * @key_flags: type &enum iwl_sta_key_flag * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection + * @reserved1: reserved * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx * @key_offset: key offset in the fw's key table + * @reserved2: reserved * @key: 16-byte unicast decryption key * @tx_secur_seq_cnt: initial RSC / PN needed for replay check * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only @@ -253,17 +286,21 @@ struct iwl_mvm_keyinfo { /** * 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 %STA_MODIFY_TID_DISABLE_TX to change this field. - * @mac_id_n_color: the Mac context this station belongs to - * @addr[ETH_ALEN]: station's MAC address + * @mac_id_n_color: the Mac context this station belongs to, + * see &enum iwl_mvm_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. - * @station_flags: look at %iwl_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 %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. @@ -274,7 +311,7 @@ struct iwl_mvm_keyinfo { * @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 %iwl_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 @@ -330,17 +367,21 @@ enum iwl_sta_type { /** * struct iwl_mvm_add_sta_cmd - 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 %STA_MODIFY_TID_DISABLE_TX to change this field. - * @mac_id_n_color: the Mac context this station belongs to - * @addr[ETH_ALEN]: station's MAC address + * @mac_id_n_color: the Mac context this station belongs to, + * see &enum iwl_mvm_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. - * @station_flags: look at %iwl_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 %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. @@ -352,7 +393,7 @@ enum iwl_sta_type { * 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 %iwl_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 @@ -401,7 +442,7 @@ struct iwl_mvm_add_sta_cmd { * ( REPLY_ADD_STA_KEY = 0x17 ) * @sta_id: index of station in uCode's station table * @key_offset: key offset in key storage - * @key_flags: type %iwl_sta_key_flag + * @key_flags: type &enum iwl_sta_key_flag * @key: key material data * @rx_secur_seq_cnt: RX security sequence counter for the key */ @@ -417,6 +458,7 @@ struct iwl_mvm_add_sta_key_common { * struct iwl_mvm_add_sta_key_cmd_v1 - add/modify sta key * @common: see &struct iwl_mvm_add_sta_key_common * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection + * @reserved: reserved * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx */ struct iwl_mvm_add_sta_key_cmd_v1 { @@ -459,6 +501,7 @@ enum iwl_mvm_add_sta_rsp_status { * struct iwl_mvm_rm_sta_cmd - Add / modify a station in the fw's station table * ( REMOVE_STA = 0x19 ) * @sta_id: the station id of the station to be removed + * @reserved: reserved */ struct iwl_mvm_rm_sta_cmd { u8 sta_id; @@ -468,12 +511,12 @@ struct iwl_mvm_rm_sta_cmd { /** * struct iwl_mvm_mgmt_mcast_key_cmd_v1 * ( MGMT_MCAST_KEY = 0x1f ) - * @ctrl_flags: %iwl_sta_key_flag - * @igtk: + * @ctrl_flags: &enum iwl_sta_key_flag + * @igtk: IGTK key material * @k1: unused * @k2: unused * @sta_id: station ID that support IGTK - * @key_id: + * @key_id: key ID * @receive_seq_cnt: initial RSC/PN needed for replay check */ struct iwl_mvm_mgmt_mcast_key_cmd_v1 { @@ -489,10 +532,10 @@ struct iwl_mvm_mgmt_mcast_key_cmd_v1 { /** * struct iwl_mvm_mgmt_mcast_key_cmd * ( MGMT_MCAST_KEY = 0x1f ) - * @ctrl_flags: %iwl_sta_key_flag + * @ctrl_flags: &enum iwl_sta_key_flag * @igtk: IGTK master key * @sta_id: station ID that support IGTK - * @key_id: + * @key_id: key ID * @receive_seq_cnt: initial RSC/PN needed for replay check */ struct iwl_mvm_mgmt_mcast_key_cmd { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h index 6371c342b96d..c7531da508fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 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 @@ -72,7 +72,7 @@ struct mvm_statistics_dbg { __le32 burst_check; __le32 burst_count; __le32 wait_for_silence_timeout_cnt; - __le32 reserved[3]; + u8 reserved[12]; } __packed; /* STATISTICS_DEBUG_API_S_VER_2 */ struct mvm_statistics_div { @@ -84,7 +84,55 @@ struct mvm_statistics_div { __le32 reserved2; } __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ +/** + * struct mvm_statistics_rx_non_phy + * @bogus_cts: CTS received when not expecting CTS + * @bogus_ack: ACK received when not expecting ACK + * @non_channel_beacons: beacons with our bss id but not on our serving channel + * @channel_beacons: beacons with our bss id and in our serving channel + * @num_missed_bcon: number of missed beacons + * @adc_rx_saturation_time: count in 0.8us units the time the ADC was in + * saturation + * @ina_detection_search_time: total time (in 0.8us) searched for INA + * @beacon_silence_rssi_a: RSSI silence after beacon frame + * @beacon_silence_rssi_b: RSSI silence after beacon frame + * @beacon_silence_rssi_c: RSSI silence after beacon frame + * @interference_data_flag: flag for interference data availability. 1 when data + * is available. + * @channel_load: counts RX Enable time in uSec + * @beacon_rssi_a: beacon RSSI on anntena A + * @beacon_rssi_b: beacon RSSI on antenna B + * @beacon_rssi_c: beacon RSSI on antenna C + * @beacon_energy_a: beacon energy on antenna A + * @beacon_energy_b: beacon energy on antenna B + * @beacon_energy_c: beacon energy on antenna C + * @num_bt_kills: number of BT "kills" (frame TX aborts) + * @mac_id: mac ID + */ struct mvm_statistics_rx_non_phy { + __le32 bogus_cts; + __le32 bogus_ack; + __le32 non_channel_beacons; + __le32 channel_beacons; + __le32 num_missed_bcon; + __le32 adc_rx_saturation_time; + __le32 ina_detection_search_time; + __le32 beacon_silence_rssi_a; + __le32 beacon_silence_rssi_b; + __le32 beacon_silence_rssi_c; + __le32 interference_data_flag; + __le32 channel_load; + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; + __le32 num_bt_kills; + __le32 mac_id; +} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_4 */ + +struct mvm_statistics_rx_non_phy_v3 { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ __le32 non_bssid_frames; /* number of frames with BSSID that @@ -121,6 +169,14 @@ struct mvm_statistics_rx_non_phy { } __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ struct mvm_statistics_rx_phy { + __le32 unresponded_rts; + __le32 rxe_frame_lmt_overrun; + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 reserved; +} __packed; /* STATISTICS_RX_PHY_API_S_VER_3 */ + +struct mvm_statistics_rx_phy_v2 { __le32 ina_cnt; __le32 fina_cnt; __le32 plcp_err; @@ -143,7 +199,7 @@ struct mvm_statistics_rx_phy { __le32 reserved; } __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */ -struct mvm_statistics_rx_ht_phy { +struct mvm_statistics_rx_ht_phy_v1 { __le32 plcp_err; __le32 overrun_err; __le32 early_overrun_err; @@ -156,7 +212,14 @@ struct mvm_statistics_rx_ht_phy { __le32 unsupport_mcs; } __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ -struct mvm_statistics_tx_non_phy { +struct mvm_statistics_rx_ht_phy { + __le32 mh_format_err; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 unsupport_mcs; +} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_2 */ + +struct mvm_statistics_tx_non_phy_v3 { __le32 preamble_cnt; __le32 rx_detected_cnt; __le32 bt_prio_defer_cnt; @@ -173,6 +236,19 @@ struct mvm_statistics_tx_non_phy { __le32 ack_or_ba_timeout_collision; } __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */ +struct mvm_statistics_tx_non_phy { + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; +} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_4 */ + #define MAX_CHAINS 3 struct mvm_statistics_tx_non_phy_agg { @@ -202,11 +278,17 @@ struct mvm_statistics_tx_channel_width { __le32 fail_per_ch_width[4]; }; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ +struct mvm_statistics_tx_v4 { + struct mvm_statistics_tx_non_phy_v3 general; + struct mvm_statistics_tx_non_phy_agg agg; + struct mvm_statistics_tx_channel_width channel_width; +} __packed; /* STATISTICS_TX_API_S_VER_4 */ + struct mvm_statistics_tx { struct mvm_statistics_tx_non_phy general; struct mvm_statistics_tx_non_phy_agg agg; struct mvm_statistics_tx_channel_width channel_width; -} __packed; /* STATISTICS_TX_API_S_VER_4 */ +} __packed; /* STATISTICS_TX_API_S_VER_5 */ struct mvm_statistics_bt_activity { @@ -220,7 +302,7 @@ struct mvm_statistics_bt_activity { __le32 lo_priority_rx_denied_cnt; } __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ -struct mvm_statistics_general_common { +struct mvm_statistics_general_common_v19 { __le32 radio_temperature; __le32 radio_voltage; struct mvm_statistics_dbg dbg; @@ -250,20 +332,56 @@ struct mvm_statistics_general_common { __le64 tx_time; } __packed; +struct mvm_statistics_general_common { + __le32 radio_temperature; + struct mvm_statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct mvm_statistics_div slow_div; + __le32 rx_enable_counter; + /* + * num_of_sos_states: + * count the number of times we have to re-tune + * in order to get out of bad PHY status + */ + __le32 num_of_sos_states; + __le32 beacon_filtered; + __le32 missed_beacons; + u8 beacon_filter_average_energy; + u8 beacon_filter_reason; + u8 beacon_filter_current_energy; + u8 beacon_filter_reserved; + __le32 beacon_filter_delta_time; + struct mvm_statistics_bt_activity bt_activity; + __le64 rx_time; + __le64 on_time_rf; + __le64 on_time_scan; + __le64 tx_time; +} __packed; /* STATISTICS_GENERAL_API_S_VER_10 */ + struct mvm_statistics_general_v8 { - struct mvm_statistics_general_common common; + struct mvm_statistics_general_common_v19 common; __le32 beacon_counter[NUM_MAC_INDEX]; u8 beacon_average_energy[NUM_MAC_INDEX]; u8 reserved[4 - (NUM_MAC_INDEX % 4)]; } __packed; /* STATISTICS_GENERAL_API_S_VER_8 */ -struct mvm_statistics_general_cdb { - struct mvm_statistics_general_common common; +struct mvm_statistics_general_cdb_v9 { + struct mvm_statistics_general_common_v19 common; __le32 beacon_counter[NUM_MAC_INDEX_CDB]; u8 beacon_average_energy[NUM_MAC_INDEX_CDB]; u8 reserved[4 - (NUM_MAC_INDEX_CDB % 4)]; } __packed; /* STATISTICS_GENERAL_API_S_VER_9 */ +struct mvm_statistics_general_cdb { + struct mvm_statistics_general_common common; + __le32 beacon_counter[MAC_INDEX_AUX]; + u8 beacon_average_energy[MAC_INDEX_AUX]; + u8 reserved[8 - MAC_INDEX_AUX]; +} __packed; /* STATISTICS_GENERAL_API_S_VER_10 */ + /** * struct mvm_statistics_load - RX statistics for multi-queue devices * @air_time: accumulated air time, per mac @@ -272,24 +390,31 @@ struct mvm_statistics_general_cdb { * @avg_energy: average RSSI, per station */ struct mvm_statistics_load { + __le32 air_time[MAC_INDEX_AUX]; + __le32 byte_count[MAC_INDEX_AUX]; + __le32 pkt_count[MAC_INDEX_AUX]; + u8 avg_energy[IWL_MVM_STATION_COUNT]; +} __packed; /* STATISTICS_RX_MAC_STATION_S_VER_3 */ + +struct mvm_statistics_load_v1 { __le32 air_time[NUM_MAC_INDEX]; __le32 byte_count[NUM_MAC_INDEX]; __le32 pkt_count[NUM_MAC_INDEX]; u8 avg_energy[IWL_MVM_STATION_COUNT]; } __packed; /* STATISTICS_RX_MAC_STATION_S_VER_1 */ -struct mvm_statistics_load_cdb { - __le32 air_time[NUM_MAC_INDEX_CDB]; - __le32 byte_count[NUM_MAC_INDEX_CDB]; - __le32 pkt_count[NUM_MAC_INDEX_CDB]; - u8 avg_energy[IWL_MVM_STATION_COUNT]; -} __packed; /* STATISTICS_RX_MAC_STATION_S_VER_2 */ - struct mvm_statistics_rx { struct mvm_statistics_rx_phy ofdm; struct mvm_statistics_rx_phy cck; struct mvm_statistics_rx_non_phy general; struct mvm_statistics_rx_ht_phy ofdm_ht; +} __packed; /* STATISTICS_RX_API_S_VER_4 */ + +struct mvm_statistics_rx_v3 { + struct mvm_statistics_rx_phy_v2 ofdm; + struct mvm_statistics_rx_phy_v2 cck; + struct mvm_statistics_rx_non_phy_v3 general; + struct mvm_statistics_rx_ht_phy_v1 ofdm_ht; } __packed; /* STATISTICS_RX_API_S_VER_3 */ /* @@ -302,17 +427,17 @@ struct mvm_statistics_rx { struct iwl_notif_statistics_v10 { __le32 flag; - struct mvm_statistics_rx rx; - struct mvm_statistics_tx tx; + struct mvm_statistics_rx_v3 rx; + struct mvm_statistics_tx_v4 tx; struct mvm_statistics_general_v8 general; } __packed; /* STATISTICS_NTFY_API_S_VER_10 */ struct iwl_notif_statistics_v11 { __le32 flag; - struct mvm_statistics_rx rx; - struct mvm_statistics_tx tx; + struct mvm_statistics_rx_v3 rx; + struct mvm_statistics_tx_v4 tx; struct mvm_statistics_general_v8 general; - struct mvm_statistics_load load_stats; + struct mvm_statistics_load_v1 load_stats; } __packed; /* STATISTICS_NTFY_API_S_VER_11 */ struct iwl_notif_statistics_cdb { @@ -320,12 +445,33 @@ struct iwl_notif_statistics_cdb { struct mvm_statistics_rx rx; struct mvm_statistics_tx tx; struct mvm_statistics_general_cdb general; - struct mvm_statistics_load_cdb load_stats; -} __packed; /* STATISTICS_NTFY_API_S_VER_12 */ + struct mvm_statistics_load load_stats; +} __packed; /* STATISTICS_NTFY_API_S_VER_13 */ -#define IWL_STATISTICS_FLG_CLEAR 0x1 -#define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2 +/** + * enum iwl_statistics_notif_flags - flags used in statistics notification + * @IWL_STATISTICS_REPLY_FLG_CLEAR: statistics were cleared after this report + */ +enum iwl_statistics_notif_flags { + IWL_STATISTICS_REPLY_FLG_CLEAR = 0x1, +}; +/** + * enum iwl_statistics_cmd_flags - flags used in statistics command + * @IWL_STATISTICS_FLG_CLEAR: request to clear statistics after the report + * that's sent after this command + * @IWL_STATISTICS_FLG_DISABLE_NOTIF: disable unilateral statistics + * notifications + */ +enum iwl_statistics_cmd_flags { + IWL_STATISTICS_FLG_CLEAR = 0x1, + IWL_STATISTICS_FLG_DISABLE_NOTIF = 0x2, +}; + +/** + * struct iwl_statistics_cmd - statistics config command + * @flags: flags from &enum iwl_statistics_cmd_flags + */ struct iwl_statistics_cmd { __le32 flags; } __packed; /* STATISTICS_CMD_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h index 86aa51b2210e..8658a983c463 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 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 @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,8 +63,6 @@ #ifndef __fw_api_tof_h__ #define __fw_api_tof_h__ -#include "fw-api.h" - /* ToF sub-group command IDs */ enum iwl_mvm_tof_sub_grp_ids { TOF_RANGE_REQ_CMD = 0x1, @@ -118,11 +116,17 @@ struct iwl_tof_config_cmd { * @bandwidth: current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz * @rate: current AP rate * @ctrl_ch_position: coding of the control channel position relative to - * the center frequency. - * 40MHz 0 below center, 1 above center - * 80MHz bits [0..1]: 0 the near 20MHz to the center, - * 1 the far 20MHz to the center - * bit[2] as above 40MHz + * the center frequency: + * + * 40 MHz + * 0 below center, 1 above center + * + * 80 MHz + * bits [0..1] + * * 0 the near 20MHz to the center, + * * 1 the far 20MHz to the center + * bit[2] + * as above 40MHz * @ftm_per_burst: FTMs per Burst * @ftm_resp_ts_avail: '0' - we don't measure over the Initial FTM Response, * '1' - we measure over the Initial FTM Response @@ -159,6 +163,7 @@ struct iwl_tof_responder_config_cmd { /** * struct iwl_tof_range_request_ext_cmd - extended range req for WLS * @tsf_timer_offset_msec: the recommended time offset (mSec) from the AP's TSF + * @reserved: reserved * @min_delta_ftm: Minimal time between two consecutive measurements, * in units of 100us. 0 means no preference by station * @ftm_format_and_bw20M: FTM Channel Spacing/Format for 20MHz: recommended @@ -268,6 +273,7 @@ enum iwl_tof_response_mode { * '1' Use MAC Address randomization according to the below * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. * Bits set to 1 shall be randomized by the UMAC + * @ap: per-AP request data */ struct iwl_tof_range_req_cmd { __le32 sub_grp_cmd_id; @@ -294,7 +300,9 @@ struct iwl_tof_gen_resp_cmd { /** * struct iwl_tof_range_rsp_ap_entry_ntfy - AP parameters (response) - * @measure_status: current APs measurement status + * @bssid: BSSID of the AP + * @measure_status: current APs measurement status, one of + * &enum iwl_tof_entry_status. * @measure_bw: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz * @rtt: The Round Trip Time that took for the last measurement for * current AP [nSec] @@ -304,6 +312,7 @@ struct iwl_tof_gen_resp_cmd { * @rssi: RSSI as uploaded in the Channel Estimation notification * @rssi_spread: The Difference between the maximum and the minimum RSSI values * measured for current AP in the current session + * @reserved: reserved * @range: Measured range [cm] * @range_variance: Measured range variance [cm] * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was @@ -330,6 +339,7 @@ struct iwl_tof_range_rsp_ap_entry_ntfy { * @request_status: status of current measurement session * @last_in_batch: reprot policy (when not all responses are uploaded at once) * @num_of_aps: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @ap: per-AP data */ struct iwl_tof_range_rsp_ntfy { u8 request_id; @@ -344,6 +354,7 @@ struct iwl_tof_range_rsp_ntfy { * struct iwl_tof_mcsi_notif - used for debug * @token: token ID for the current session * @role: '0' - initiator, '1' - responder + * @reserved: reserved * @initiator_bssid: initiator machine * @responder_bssid: responder machine * @mcsi_buffer: debug data @@ -376,6 +387,7 @@ struct iwl_tof_neighbor_report { /** * struct iwl_tof_range_abort_cmd * @request_id: corresponds to a range request + * @reserved: reserved */ struct iwl_tof_range_abort_cmd { __le32 sub_grp_cmd_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 1360ebfdc51b..97d7eed32622 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -74,6 +74,7 @@ * Otherwise, use rate_n_flags from the TX command * @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected * Must set TX_CMD_FLG_ACK with this flag. + * @TX_CMD_FLG_TXOP_PROT: TXOP protection requested * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) @@ -177,29 +178,6 @@ enum iwl_tx_cmd_sec_ctrl { TX_CMD_SEC_KEY_FROM_TABLE = 0x10, }; -/* TODO: how does these values are OK with only 16 bit variable??? */ -/* - * TX command next frame info - * - * bits 0:2 - security control (TX_CMD_SEC_*) - * bit 3 - immediate ACK required - * bit 4 - rate is taken from STA table - * bit 5 - frame belongs to BA stream - * bit 6 - immediate BA response expected - * bit 7 - unused - * bits 8:15 - Station ID - * bits 16:31 - rate - */ -#define TX_CMD_NEXT_FRAME_ACK_MSK (0x8) -#define TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10) -#define TX_CMD_NEXT_FRAME_BA_MSK (0x20) -#define TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40) -#define TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8) -#define TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00) -#define TX_CMD_NEXT_FRAME_STA_ID_POS (8) -#define TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000) -#define TX_CMD_NEXT_FRAME_RATE_POS (16) - /* * TX command Frame life time in us - to be written in pm_frame_timeout */ @@ -224,7 +202,7 @@ enum iwl_tx_cmd_sec_ctrl { /** * enum iwl_tx_offload_assist_flags_pos - set %iwl_tx_cmd offload_assist values - * @TX_CMD_OFFLD_IP_HDR_OFFSET: offset to start of IP header (in words) + * @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 @@ -258,22 +236,27 @@ enum iwl_tx_offload_assist_flags_pos { * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration * @tx_flags: combination of TX_CMD_FLG_* + * @scratch: scratch buffer used by the device * @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 * @sec_ctl: security control, TX_CMD_SEC_* * @initial_rate_index: index into the the rate table for initial TX attempt. * Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames. + * @reserved2: reserved * @key: security key - * @next_frame_flags: TX_CMD_SEC_* and TX_CMD_NEXT_FRAME_* + * @reserved3: reserved * @life_time: frame life time (usecs??) * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt + * btkill_cnd + reserved), first 32 bits. "0" disables usage. * @dram_msb_ptr: upper bits of the scratch physical address * @rts_retry_limit: max attempts for RTS * @data_retry_limit: max attempts to send the data packet - * @tid_spec: TID/tspec + * @tid_tspec: TID/tspec * @pm_frame_timeout: PM TX frame timeout + * @reserved4: reserved + * @payload: payload (same as @hdr) + * @hdr: 802.11 header (same as @payload) * * The byte count (both len and next_frame_len) includes MAC header * (24/26/30/32 bytes) @@ -327,10 +310,11 @@ struct iwl_dram_sec_info { * ( TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration - * @tx_flags: combination of &iwl_tx_cmd_flags + * @flags: combination of &enum iwl_tx_cmd_flags * @dram_info: FW internal DRAM storage * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* + * @hdr: 802.11 header */ struct iwl_tx_cmd_gen2 { __le16 len; @@ -504,7 +488,7 @@ enum iwl_tx_agg_status { /** * struct agg_tx_status - per packet TX aggregation status - * @status: enum iwl_tx_agg_status + * @status: See &enum iwl_tx_agg_status * @sequence: Sequence # for this frame's Tx cmd (not SSN!) */ struct agg_tx_status { @@ -529,6 +513,63 @@ struct agg_tx_status { #define IWL_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4) /** + * struct iwl_mvm_tx_resp_v3 - notifies that fw is TXing a packet + * ( REPLY_TX = 0x1c ) + * @frame_count: 1 no aggregation, >1 aggregation + * @bt_kill_count: num of times blocked by bluetooth (unused for agg) + * @failure_rts: num of failures due to unsuccessful RTS + * @failure_frame: num failures due to no ACK (unused for agg) + * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the + * Tx of all the batch. RATE_MCS_* + * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. + * for agg: RTS + CTS + aggregation tx time + block-ack time. + * in usec. + * @pa_status: tx power info + * @pa_integ_res_a: tx power info + * @pa_integ_res_b: tx power info + * @pa_integ_res_c: tx power info + * @measurement_req_id: tx power info + * @reduced_tpc: transmit power reduction used + * @reserved: reserved + * @tfd_info: TFD information set by the FH + * @seq_ctl: sequence control from the Tx cmd + * @byte_cnt: byte count from the Tx cmd + * @tlc_info: TLC rate info + * @ra_tid: bits [3:0] = ra, bits [7:4] = tid + * @frame_ctrl: frame control + * @status: for non-agg: frame status TX_STATUS_* + * for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields + * follow this one, up to frame_count. Length in @frame_count. + * + * After the array of statuses comes the SSN of the SCD. Look at + * %iwl_mvm_get_scd_ssn for more details. + */ +struct iwl_mvm_tx_resp_v3 { + u8 frame_count; + u8 bt_kill_count; + u8 failure_rts; + u8 failure_frame; + __le32 initial_rate; + __le16 wireless_media_time; + + u8 pa_status; + u8 pa_integ_res_a[3]; + u8 pa_integ_res_b[3]; + u8 pa_integ_res_c[3]; + __le16 measurement_req_id; + u8 reduced_tpc; + u8 reserved; + + __le32 tfd_info; + __le16 seq_ctl; + __le16 byte_cnt; + u8 tlc_info; + u8 ra_tid; + __le16 frame_ctrl; + struct agg_tx_status status[]; +} __packed; /* TX_RSP_API_S_VER_3 */ + +/** * struct iwl_mvm_tx_resp - notifies that fw is TXing a packet * ( REPLY_TX = 0x1c ) * @frame_count: 1 no aggregation, >1 aggregation @@ -545,6 +586,8 @@ struct agg_tx_status { * @pa_integ_res_b: tx power info * @pa_integ_res_c: tx power info * @measurement_req_id: tx power info + * @reduced_tpc: transmit power reduction used + * @reserved: reserved * @tfd_info: TFD information set by the FH * @seq_ctl: sequence control from the Tx cmd * @byte_cnt: byte count from the Tx cmd @@ -552,9 +595,8 @@ struct agg_tx_status { * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control * @tx_queue: TX queue for this response + * @reserved2: reserved for padding/alignment * @status: for non-agg: frame status TX_STATUS_* - * for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields - * follow this one, up to frame_count. * For version 6 TX response isn't received for aggregation at all. * * After the array of statuses comes the SSN of the SCD. Look at @@ -582,26 +624,19 @@ struct iwl_mvm_tx_resp { u8 tlc_info; u8 ra_tid; __le16 frame_ctrl; - union { - struct { - struct agg_tx_status status; - } v3;/* TX_RSP_API_S_VER_3 */ - struct { - __le16 tx_queue; - __le16 reserved2; - struct agg_tx_status status; - } v6; - }; + __le16 tx_queue; + __le16 reserved2; + struct agg_tx_status status; } __packed; /* TX_RSP_API_S_VER_6 */ /** * struct iwl_mvm_ba_notif - notifies about reception of BA * ( BA_NOTIF = 0xc5 ) - * @sta_addr_lo32: lower 32 bits of the MAC address - * @sta_addr_hi16: upper 16 bits of the MAC address + * @sta_addr: MAC address + * @reserved: reserved * @sta_id: Index of recipient (BA-sending) station in fw's station table * @tid: tid of the session - * @seq_ctl: + * @seq_ctl: sequence control field * @bitmap: the bitmap of the BA notification as seen in the air * @scd_flow: the tx queue this BA relates to * @scd_ssn: the index of the last contiguously sent packet @@ -610,10 +645,10 @@ struct iwl_mvm_tx_resp { * @reduced_txp: power reduced according to TPC. This is the actual value and * not a copy from the LQ command. Thus, if not the first rate was used * for Tx-ing then this value will be set to 0 by FW. + * @reserved1: reserved */ struct iwl_mvm_ba_notif { - __le32 sta_addr_lo32; - __le16 sta_addr_hi16; + u8 sta_addr[ETH_ALEN]; __le16 reserved; u8 sta_id; @@ -633,13 +668,15 @@ struct iwl_mvm_ba_notif { * @q_num: TFD queue number * @tfd_index: Index of first un-acked frame in the TFD queue * @scd_queue: For debug only - the physical queue the TFD queue is bound to + * @tid: TID of the queue (0-7) + * @reserved: reserved for alignment */ struct iwl_mvm_compressed_ba_tfd { __le16 q_num; __le16 tfd_index; u8 scd_queue; - u8 reserved; - __le16 reserved2; + u8 tid; + u8 reserved[2]; } __packed; /* COMPRESSED_BA_TFD_API_S_VER_1 */ /** @@ -687,11 +724,12 @@ enum iwl_mvm_ba_resp_flags { * @query_frame_cnt: SCD query frame count * @txed: number of frames sent in the aggregation (all-TIDs) * @done: number of frames that were Acked by the BA (all-TIDs) + * @reserved: reserved (for alignment) * @wireless_time: Wireless-media time * @tx_rate: the rate the aggregation was sent at * @tfd_cnt: number of TFD-Q elements * @ra_tid_cnt: number of RATID-Q elements - * @ba_tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd + * @tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd * for details. * @ra_tid: array of RA-TID queue status updates. For debug purposes only. See * &iwl_mvm_compressed_ba_ratid for more details. @@ -765,6 +803,7 @@ struct iwl_mac_beacon_cmd_v7 { * struct iwl_mac_beacon_cmd - beacon template command with offloaded CSA * @byte_cnt: byte count of the beacon frame * @flags: for future use + * @reserved: reserved * @data: see &iwl_mac_beacon_cmd_data */ struct iwl_mac_beacon_cmd { @@ -809,12 +848,24 @@ enum iwl_dump_control { * @flush_ctl: control flags * @reserved: reserved */ -struct iwl_tx_path_flush_cmd { +struct iwl_tx_path_flush_cmd_v1 { __le32 queues_ctl; __le16 flush_ctl; __le16 reserved; } __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */ +/** + * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command + * @sta_id: station ID to flush + * @tid_mask: TID mask to flush + * @reserved: reserved + */ +struct iwl_tx_path_flush_cmd { + __le32 sta_id; + __le16 tid_mask; + __le16 reserved; +} __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_2 */ + /* Available options for the SCD_QUEUE_CFG HCMD */ enum iwl_scd_cfg_actions { SCD_CFG_DISABLE_QUEUE = 0x0, @@ -824,16 +875,17 @@ enum iwl_scd_cfg_actions { /** * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command - * @token: + * @token: unused * @sta_id: station id - * @tid: + * @tid: TID * @scd_queue: scheduler queue to confiug * @action: 1 queue enable, 0 queue disable, 2 change txq's tid owner - * Value is one of %iwl_scd_cfg_actions options + * Value is one of &enum iwl_scd_cfg_actions options * @aggregate: 1 aggregated queue, 0 otherwise - * @tx_fifo: %enum iwl_mvm_tx_fifo + * @tx_fifo: &enum iwl_mvm_tx_fifo * @window: BA window size * @ssn: SSN for the BA agreement + * @reserved: reserved */ struct iwl_scd_txq_cfg_cmd { u8 token; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index f545c5f9e4e3..aad265dcfaf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -130,181 +130,547 @@ enum iwl_mvm_tx_fifo { }; -/* commands */ -enum { +/** + * enum iwl_legacy_cmds - legacy group command IDs + */ +enum iwl_legacy_cmds { + /** + * @MVM_ALIVE: + * Alive data from the firmware, as described in + * &struct mvm_alive_resp_v3 or &struct mvm_alive_resp. + */ MVM_ALIVE = 0x1, + + /** + * @REPLY_ERROR: Cause an error in the firmware, for testing purposes. + */ REPLY_ERROR = 0x2, + + /** + * @ECHO_CMD: Send data to the device to have it returned immediately. + */ ECHO_CMD = 0x3, + /** + * @INIT_COMPLETE_NOTIF: Notification that initialization is complete. + */ INIT_COMPLETE_NOTIF = 0x4, - /* PHY context commands */ + /** + * @PHY_CONTEXT_CMD: + * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd. + */ PHY_CONTEXT_CMD = 0x8, + + /** + * @DBG_CFG: Debug configuration command. + */ DBG_CFG = 0x9, + + /** + * @ANTENNA_COUPLING_NOTIFICATION: + * Antenna coupling data, &struct iwl_mvm_antenna_coupling_notif + */ ANTENNA_COUPLING_NOTIFICATION = 0xa, - /* UMAC scan commands */ + /** + * @SCAN_ITERATION_COMPLETE_UMAC: + * Firmware indicates a scan iteration completed, using + * &struct iwl_umac_scan_iter_complete_notif. + */ SCAN_ITERATION_COMPLETE_UMAC = 0xb5, + + /** + * @SCAN_CFG_CMD: + * uses &struct iwl_scan_config_v1 or &struct iwl_scan_config + */ SCAN_CFG_CMD = 0xc, + + /** + * @SCAN_REQ_UMAC: uses &struct iwl_scan_req_umac + */ SCAN_REQ_UMAC = 0xd, + + /** + * @SCAN_ABORT_UMAC: uses &struct iwl_umac_scan_abort + */ SCAN_ABORT_UMAC = 0xe, + + /** + * @SCAN_COMPLETE_UMAC: uses &struct iwl_umac_scan_complete + */ SCAN_COMPLETE_UMAC = 0xf, + /** + * @BA_WINDOW_STATUS_NOTIFICATION_ID: + * uses &struct iwl_ba_window_status_notif + */ BA_WINDOW_STATUS_NOTIFICATION_ID = 0x13, - /* station table */ + /** + * @ADD_STA_KEY: + * &struct iwl_mvm_add_sta_key_cmd_v1 or + * &struct iwl_mvm_add_sta_key_cmd. + */ ADD_STA_KEY = 0x17, + + /** + * @ADD_STA: + * &struct iwl_mvm_add_sta_cmd or &struct iwl_mvm_add_sta_cmd_v7. + */ ADD_STA = 0x18, + + /** + * @REMOVE_STA: &struct iwl_mvm_rm_sta_cmd + */ REMOVE_STA = 0x19, - /* paging get item */ + /** + * @FW_GET_ITEM_CMD: uses &struct iwl_fw_get_item_cmd + */ FW_GET_ITEM_CMD = 0x1a, - /* TX */ + /** + * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2, + * response in &struct iwl_mvm_tx_resp or + * &struct iwl_mvm_tx_resp_v3 + */ TX_CMD = 0x1c, + + /** + * @TXPATH_FLUSH: &struct iwl_tx_path_flush_cmd + */ TXPATH_FLUSH = 0x1e, + + /** + * @MGMT_MCAST_KEY: + * &struct iwl_mvm_mgmt_mcast_key_cmd or + * &struct iwl_mvm_mgmt_mcast_key_cmd_v1 + */ MGMT_MCAST_KEY = 0x1f, /* scheduler config */ + /** + * @SCD_QUEUE_CFG: &struct iwl_scd_txq_cfg_cmd for older hardware, + * &struct iwl_tx_queue_cfg_cmd with &struct iwl_tx_queue_cfg_rsp + * for newer (A000) hardware. + */ SCD_QUEUE_CFG = 0x1d, - /* global key */ + /** + * @WEP_KEY: uses &struct iwl_mvm_wep_key_cmd + */ WEP_KEY = 0x20, - /* Memory */ + /** + * @SHARED_MEM_CFG: + * retrieve shared memory configuration - response in + * &struct iwl_shared_mem_cfg + */ SHARED_MEM_CFG = 0x25, - /* TDLS */ + /** + * @TDLS_CHANNEL_SWITCH_CMD: uses &struct iwl_tdls_channel_switch_cmd + */ TDLS_CHANNEL_SWITCH_CMD = 0x27, + + /** + * @TDLS_CHANNEL_SWITCH_NOTIFICATION: + * uses &struct iwl_tdls_channel_switch_notif + */ TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, + + /** + * @TDLS_CONFIG_CMD: + * &struct iwl_tdls_config_cmd, response in &struct iwl_tdls_config_res + */ TDLS_CONFIG_CMD = 0xa7, - /* MAC and Binding commands */ + /** + * @MAC_CONTEXT_CMD: &struct iwl_mac_ctx_cmd + */ MAC_CONTEXT_CMD = 0x28, + + /** + * @TIME_EVENT_CMD: + * &struct iwl_time_event_cmd, response in &struct iwl_time_event_resp + */ TIME_EVENT_CMD = 0x29, /* both CMD and response */ + + /** + * @TIME_EVENT_NOTIFICATION: &struct iwl_time_event_notif + */ TIME_EVENT_NOTIFICATION = 0x2a, + + /** + * @BINDING_CONTEXT_CMD: + * &struct iwl_binding_cmd or &struct iwl_binding_cmd_v1 + */ BINDING_CONTEXT_CMD = 0x2b, + + /** + * @TIME_QUOTA_CMD: &struct iwl_time_quota_cmd + */ TIME_QUOTA_CMD = 0x2c, + + /** + * @NON_QOS_TX_COUNTER_CMD: + * command is &struct iwl_nonqos_seq_query_cmd + */ NON_QOS_TX_COUNTER_CMD = 0x2d, + /** + * @LQ_CMD: using &struct iwl_lq_cmd + */ LQ_CMD = 0x4e, - /* paging block to FW cpu2 */ + /** + * @FW_PAGING_BLOCK_CMD: + * &struct iwl_fw_paging_cmd + */ FW_PAGING_BLOCK_CMD = 0x4f, - /* Scan offload */ + /** + * @SCAN_OFFLOAD_REQUEST_CMD: uses &struct iwl_scan_req_lmac + */ SCAN_OFFLOAD_REQUEST_CMD = 0x51, + + /** + * @SCAN_OFFLOAD_ABORT_CMD: abort the scan - no further contents + */ SCAN_OFFLOAD_ABORT_CMD = 0x52, + + /** + * @HOT_SPOT_CMD: uses &struct iwl_hs20_roc_req + */ HOT_SPOT_CMD = 0x53, + + /** + * @SCAN_OFFLOAD_COMPLETE: + * notification, &struct iwl_periodic_scan_complete + */ SCAN_OFFLOAD_COMPLETE = 0x6D, + + /** + * @SCAN_OFFLOAD_UPDATE_PROFILES_CMD: + * update scan offload (scheduled scan) profiles/blacklist/etc. + */ SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, - SCAN_OFFLOAD_CONFIG_CMD = 0x6f, + + /** + * @MATCH_FOUND_NOTIFICATION: scan match found + */ MATCH_FOUND_NOTIFICATION = 0xd9, + + /** + * @SCAN_ITERATION_COMPLETE: + * uses &struct iwl_lmac_scan_complete_notif + */ SCAN_ITERATION_COMPLETE = 0xe7, /* Phy */ + /** + * @PHY_CONFIGURATION_CMD: &struct iwl_phy_cfg_cmd + */ PHY_CONFIGURATION_CMD = 0x6a, + + /** + * @CALIB_RES_NOTIF_PHY_DB: &struct iwl_calib_res_notif_phy_db + */ CALIB_RES_NOTIF_PHY_DB = 0x6b, + + /** + * @PHY_DB_CMD: &struct iwl_phy_db_cmd + */ PHY_DB_CMD = 0x6c, - /* ToF - 802.11mc FTM */ + /** + * @TOF_CMD: &struct iwl_tof_config_cmd + */ TOF_CMD = 0x10, + + /** + * @TOF_NOTIFICATION: &struct iwl_tof_gen_resp_cmd + */ TOF_NOTIFICATION = 0x11, - /* Power - legacy power table command */ + /** + * @POWER_TABLE_CMD: &struct iwl_device_power_cmd + */ POWER_TABLE_CMD = 0x77, + + /** + * @PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION: + * &struct iwl_uapsd_misbehaving_ap_notif + */ PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, + + /** + * @LTR_CONFIG: &struct iwl_ltr_config_cmd + */ LTR_CONFIG = 0xee, - /* Thermal Throttling*/ + /** + * @REPLY_THERMAL_MNG_BACKOFF: + * Thermal throttling command + */ REPLY_THERMAL_MNG_BACKOFF = 0x7e, - /* Set/Get DC2DC frequency tune */ + /** + * @DC2DC_CONFIG_CMD: + * Set/Get DC2DC frequency tune + * Command is &struct iwl_dc2dc_config_cmd, + * response is &struct iwl_dc2dc_config_resp + */ DC2DC_CONFIG_CMD = 0x83, - /* NVM */ + /** + * @NVM_ACCESS_CMD: using &struct iwl_nvm_access_cmd + */ NVM_ACCESS_CMD = 0x88, - SET_CALIB_DEFAULT_CMD = 0x8e, - + /** + * @BEACON_NOTIFICATION: &struct iwl_extended_beacon_notif + */ BEACON_NOTIFICATION = 0x90, + + /** + * @BEACON_TEMPLATE_CMD: + * Uses one of &struct iwl_mac_beacon_cmd_v6, + * &struct iwl_mac_beacon_cmd_v7 or &struct iwl_mac_beacon_cmd + * depending on the device version. + */ BEACON_TEMPLATE_CMD = 0x91, + /** + * @TX_ANT_CONFIGURATION_CMD: &struct iwl_tx_ant_cfg_cmd + */ TX_ANT_CONFIGURATION_CMD = 0x98, + + /** + * @STATISTICS_CMD: + * one of &struct iwl_statistics_cmd, + * &struct iwl_notif_statistics_v11, + * &struct iwl_notif_statistics_v10, + * &struct iwl_notif_statistics_cdb + */ STATISTICS_CMD = 0x9c, + + /** + * @STATISTICS_NOTIFICATION: + * one of &struct iwl_notif_statistics_v10, + * &struct iwl_notif_statistics_v11, + * &struct iwl_notif_statistics_cdb + */ STATISTICS_NOTIFICATION = 0x9d, + + /** + * @EOSP_NOTIFICATION: + * Notify that a service period ended, + * &struct iwl_mvm_eosp_notification + */ EOSP_NOTIFICATION = 0x9e, + + /** + * @REDUCE_TX_POWER_CMD: + * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd + */ REDUCE_TX_POWER_CMD = 0x9f, - /* RF-KILL commands and notifications */ - CARD_STATE_CMD = 0xa0, + /** + * @CARD_STATE_NOTIFICATION: + * Card state (RF/CT kill) notification, + * uses &struct iwl_card_state_notif + */ CARD_STATE_NOTIFICATION = 0xa1, + /** + * @MISSED_BEACONS_NOTIFICATION: &struct iwl_missed_beacons_notif + */ MISSED_BEACONS_NOTIFICATION = 0xa2, - /* Power - new power table command */ + /** + * @MAC_PM_POWER_TABLE: using &struct iwl_mac_power_cmd + */ MAC_PM_POWER_TABLE = 0xa9, + /** + * @MFUART_LOAD_NOTIFICATION: &struct iwl_mfuart_load_notif + */ MFUART_LOAD_NOTIFICATION = 0xb1, + /** + * @RSS_CONFIG_CMD: &struct iwl_rss_config_cmd + */ RSS_CONFIG_CMD = 0xb3, + /** + * @REPLY_RX_PHY_CMD: &struct iwl_rx_phy_info + */ REPLY_RX_PHY_CMD = 0xc0, + + /** + * @REPLY_RX_MPDU_CMD: + * &struct iwl_rx_mpdu_res_start or &struct iwl_rx_mpdu_desc + */ REPLY_RX_MPDU_CMD = 0xc1, + + /** + * @FRAME_RELEASE: + * Frame release (reorder helper) notification, uses + * &struct iwl_frame_release + */ FRAME_RELEASE = 0xc3, + + /** + * @BA_NOTIF: + * BlockAck notification, uses &struct iwl_mvm_compressed_ba_notif + * or &struct iwl_mvm_ba_notif depending on the HW + */ BA_NOTIF = 0xc5, /* Location Aware Regulatory */ + /** + * @MCC_UPDATE_CMD: using &struct iwl_mcc_update_cmd + */ MCC_UPDATE_CMD = 0xc8, + + /** + * @MCC_CHUB_UPDATE_CMD: using &struct iwl_mcc_chub_notif + */ MCC_CHUB_UPDATE_CMD = 0xc9, + /** + * @MARKER_CMD: trace marker command, uses &struct iwl_mvm_marker + */ MARKER_CMD = 0xcb, - /* BT Coex */ - BT_COEX_PRIO_TABLE = 0xcc, - BT_COEX_PROT_ENV = 0xcd, + /** + * @BT_PROFILE_NOTIFICATION: &struct iwl_bt_coex_profile_notif + */ BT_PROFILE_NOTIFICATION = 0xce, + + /** + * @BT_CONFIG: &struct iwl_bt_coex_cmd + */ BT_CONFIG = 0x9b, - BT_COEX_UPDATE_SW_BOOST = 0x5a, + + /** + * @BT_COEX_UPDATE_CORUN_LUT: + * &struct iwl_bt_coex_corun_lut_update_cmd + */ BT_COEX_UPDATE_CORUN_LUT = 0x5b, + + /** + * @BT_COEX_UPDATE_REDUCED_TXP: + * &struct iwl_bt_coex_reduced_txp_update_cmd + */ BT_COEX_UPDATE_REDUCED_TXP = 0x5c, + + /** + * @BT_COEX_CI: &struct iwl_bt_coex_ci_cmd + */ BT_COEX_CI = 0x5d, + /** + * @REPLY_SF_CFG_CMD: &struct iwl_sf_cfg_cmd + */ REPLY_SF_CFG_CMD = 0xd1, + /** + * @REPLY_BEACON_FILTERING_CMD: &struct iwl_beacon_filter_cmd + */ REPLY_BEACON_FILTERING_CMD = 0xd2, - /* DTS measurements */ - CMD_DTS_MEASUREMENT_TRIGGER = 0xdc, + /** + * @DTS_MEASUREMENT_NOTIFICATION: + * &struct iwl_dts_measurement_notif_v1 or + * &struct iwl_dts_measurement_notif_v2 + */ DTS_MEASUREMENT_NOTIFICATION = 0xdd, - REPLY_DEBUG_CMD = 0xf0, + /** + * @LDBG_CONFIG_CMD: configure continuous trace recording + */ LDBG_CONFIG_CMD = 0xf6, + + /** + * @DEBUG_LOG_MSG: Debugging log data from firmware + */ DEBUG_LOG_MSG = 0xf7, + /** + * @BCAST_FILTER_CMD: &struct iwl_bcast_filter_cmd + */ BCAST_FILTER_CMD = 0xcf, + + /** + * @MCAST_FILTER_CMD: &struct iwl_mcast_filter_cmd + */ MCAST_FILTER_CMD = 0xd0, - /* D3 commands/notifications */ + /** + * @D3_CONFIG_CMD: &struct iwl_d3_manager_config + */ D3_CONFIG_CMD = 0xd3, + + /** + * @PROT_OFFLOAD_CONFIG_CMD: Depending on firmware, uses one of + * &struct iwl_proto_offload_cmd_v1, &struct iwl_proto_offload_cmd_v2, + * &struct iwl_proto_offload_cmd_v3_small, + * &struct iwl_proto_offload_cmd_v3_large + */ PROT_OFFLOAD_CONFIG_CMD = 0xd4, + + /** + * @OFFLOADS_QUERY_CMD: + * No data in command, response in &struct iwl_wowlan_status + */ OFFLOADS_QUERY_CMD = 0xd5, + + /** + * @REMOTE_WAKE_CONFIG_CMD: &struct iwl_wowlan_remote_wake_config + */ REMOTE_WAKE_CONFIG_CMD = 0xd6, + + /** + * @D0I3_END_CMD: End D0i3/D3 state, no command data + */ D0I3_END_CMD = 0xed, - /* for WoWLAN in particular */ + /** + * @WOWLAN_PATTERNS: &struct iwl_wowlan_patterns_cmd + */ WOWLAN_PATTERNS = 0xe0, + + /** + * @WOWLAN_CONFIGURATION: &struct iwl_wowlan_config_cmd + */ WOWLAN_CONFIGURATION = 0xe1, + + /** + * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd + */ WOWLAN_TSC_RSC_PARAM = 0xe2, + + /** + * @WOWLAN_TKIP_PARAM: &struct iwl_wowlan_tkip_params_cmd + */ WOWLAN_TKIP_PARAM = 0xe3, + + /** + * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd + */ WOWLAN_KEK_KCK_MATERIAL = 0xe4, + + /** + * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status + */ WOWLAN_GET_STATUSES = 0xe5, - WOWLAN_TX_POWER_PER_DB = 0xe6, - /* and for NetDetect */ + /** + * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: + * No command data, response is &struct iwl_scan_offload_profiles_query + */ SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, - SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD = 0x58, - SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD = 0x59, - - REPLY_MAX = 0xff, }; /* Please keep this enum *SORTED* by hex value. @@ -316,45 +682,169 @@ enum iwl_mac_conf_subcmd_ids { CHANNEL_SWITCH_NOA_NOTIF = 0xFF, }; +/** + * enum iwl_phy_ops_subcmd_ids - PHY group commands + */ enum iwl_phy_ops_subcmd_ids { + /** + * @CMD_DTS_MEASUREMENT_TRIGGER_WIDE: + * Uses either &struct iwl_dts_measurement_cmd or + * &struct iwl_ext_dts_measurement_cmd + */ CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, + + /** + * @CTDP_CONFIG_CMD: &struct iwl_mvm_ctdp_cmd + */ CTDP_CONFIG_CMD = 0x03, + + /** + * @TEMP_REPORTING_THRESHOLDS_CMD: &struct temp_report_ths_cmd + */ TEMP_REPORTING_THRESHOLDS_CMD = 0x04, + + /** + * @GEO_TX_POWER_LIMIT: &struct iwl_geo_tx_power_profiles_cmd + */ GEO_TX_POWER_LIMIT = 0x05, + + /** + * @CT_KILL_NOTIFICATION: &struct ct_kill_notif + */ CT_KILL_NOTIFICATION = 0xFE, + + /** + * @DTS_MEASUREMENT_NOTIF_WIDE: + * &struct iwl_dts_measurement_notif_v1 or + * &struct iwl_dts_measurement_notif_v2 + */ DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; +/** + * enum iwl_system_subcmd_ids - system group command IDs + */ enum iwl_system_subcmd_ids { + /** + * @SHARED_MEM_CFG_CMD: + * response in &struct iwl_shared_mem_cfg or + * &struct iwl_shared_mem_cfg_v2 + */ SHARED_MEM_CFG_CMD = 0x0, + + /** + * @INIT_EXTENDED_CFG_CMD: &struct iwl_init_extended_cfg_cmd + */ INIT_EXTENDED_CFG_CMD = 0x03, }; +/** + * enum iwl_data_path_subcmd_ids - data path group commands + */ enum iwl_data_path_subcmd_ids { + /** + * @DQA_ENABLE_CMD: &struct iwl_dqa_enable_cmd + */ DQA_ENABLE_CMD = 0x0, + + /** + * @UPDATE_MU_GROUPS_CMD: &struct iwl_mu_group_mgmt_cmd + */ UPDATE_MU_GROUPS_CMD = 0x1, + + /** + * @TRIGGER_RX_QUEUES_NOTIF_CMD: &struct iwl_rxq_sync_cmd + */ TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, + + /** + * @STA_PM_NOTIF: &struct iwl_mvm_pm_state_notification + */ STA_PM_NOTIF = 0xFD, + + /** + * @MU_GROUP_MGMT_NOTIF: &struct iwl_mu_group_mgmt_notif + */ MU_GROUP_MGMT_NOTIF = 0xFE, + + /** + * @RX_QUEUES_NOTIFICATION: &struct iwl_rxq_sync_notification + */ RX_QUEUES_NOTIFICATION = 0xFF, }; +/** + * enum iwl_prot_offload_subcmd_ids - protocol offload commands + */ enum iwl_prot_offload_subcmd_ids { + /** + * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif + */ STORED_BEACON_NTF = 0xFF, }; +/** + * enum iwl_regulatory_and_nvm_subcmd_ids - regulatory/NVM commands + */ enum iwl_regulatory_and_nvm_subcmd_ids { + /** + * @NVM_ACCESS_COMPLETE: &struct iwl_nvm_access_complete_cmd + */ NVM_ACCESS_COMPLETE = 0x0, + + /** + * @NVM_GET_INFO: + * Command is &struct iwl_nvm_get_info, + * response is &struct iwl_nvm_get_info_rsp + */ + NVM_GET_INFO = 0x2, }; +/** + * enum iwl_debug_cmds - debug commands + */ enum iwl_debug_cmds { + /** + * @LMAC_RD_WR: + * LMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and + * &struct iwl_dbg_mem_access_rsp + */ LMAC_RD_WR = 0x0, + /** + * @UMAC_RD_WR: + * UMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and + * &struct iwl_dbg_mem_access_rsp + */ UMAC_RD_WR = 0x1, + /** + * @MFU_ASSERT_DUMP_NTF: + * &struct iwl_mfu_assert_dump_notif + */ MFU_ASSERT_DUMP_NTF = 0xFE, }; -/* command groups */ -enum { +/** + * enum iwl_mvm_command_groups - command groups for the firmware + * @LEGACY_GROUP: legacy group, uses command IDs from &enum iwl_legacy_cmds + * @LONG_GROUP: legacy group with long header, also uses command IDs + * from &enum iwl_legacy_cmds + * @SYSTEM_GROUP: system group, uses command IDs from + * &enum iwl_system_subcmd_ids + * @MAC_CONF_GROUP: MAC configuration group, uses command IDs from + * &enum iwl_mac_conf_subcmd_ids + * @PHY_OPS_GROUP: PHY operations group, uses command IDs from + * &enum iwl_phy_ops_subcmd_ids + * @DATA_PATH_GROUP: data path group, uses command IDs from + * &enum iwl_data_path_subcmd_ids + * @NAN_GROUP: NAN group, uses command IDs from &enum iwl_nan_subcmd_ids + * @TOF_GROUP: TOF group, uses command IDs from &enum iwl_tof_subcmd_ids + * @PROT_OFFLOAD_GROUP: protocol offload group, uses command IDs from + * &enum iwl_prot_offload_subcmd_ids + * @REGULATORY_AND_NVM_GROUP: regulatory/NVM group, uses command IDs from + * &enum iwl_regulatory_and_nvm_subcmd_ids + * @DEBUG_GROUP: Debug group, uses command IDs from &enum iwl_debug_cmds + */ +enum iwl_mvm_command_groups { LEGACY_GROUP = 0x0, LONG_GROUP = 0x1, SYSTEM_GROUP = 0x2, @@ -390,13 +880,13 @@ struct iwl_tx_ant_cfg_cmd { __le32 valid; } __packed; -/* - * Calibration control struct. +/** + * struct iwl_calib_ctrl - Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to - * flow triggers. + * flow triggers, using &enum iwl_calib_cfg * @event_trigger: bitmap for which calibrations to perform according to - * event triggers. + * event triggers, using &enum iwl_calib_cfg */ struct iwl_calib_ctrl { __le32 flow_trigger; @@ -428,8 +918,10 @@ enum iwl_calib_cfg { IWL_CALIB_CFG_AGC_IDX = BIT(18), }; -/* - * Phy configuration command. +/** + * struct iwl_phy_cfg_cmd - Phy configuration command + * @phy_cfg: PHY configuration value, uses &enum iwl_fw_phy_cfg + * @calib_control: calibration control data */ struct iwl_phy_cfg_cmd { __le32 phy_cfg; @@ -448,15 +940,39 @@ struct iwl_phy_cfg_cmd { #define PHY_CFG_RX_CHAIN_C BIT(14) -/* Target of the NVM_ACCESS_CMD */ -enum { +/** + * enum iwl_nvm_access_op - NVM access opcode + * @IWL_NVM_READ: read NVM + * @IWL_NVM_WRITE: write NVM + */ +enum iwl_nvm_access_op { + IWL_NVM_READ = 0, + IWL_NVM_WRITE = 1, +}; + +/** + * enum iwl_nvm_access_target - target of the NVM_ACCESS_CMD + * @NVM_ACCESS_TARGET_CACHE: access the cache + * @NVM_ACCESS_TARGET_OTP: access the OTP + * @NVM_ACCESS_TARGET_EEPROM: access the EEPROM + */ +enum iwl_nvm_access_target { NVM_ACCESS_TARGET_CACHE = 0, NVM_ACCESS_TARGET_OTP = 1, NVM_ACCESS_TARGET_EEPROM = 2, }; -/* Section types for NVM_ACCESS_CMD */ -enum { +/** + * enum iwl_nvm_section_type - section types for NVM_ACCESS_CMD + * @NVM_SECTION_TYPE_SW: software section + * @NVM_SECTION_TYPE_REGULATORY: regulatory section + * @NVM_SECTION_TYPE_CALIBRATION: calibration section + * @NVM_SECTION_TYPE_PRODUCTION: production section + * @NVM_SECTION_TYPE_MAC_OVERRIDE: MAC override section + * @NVM_SECTION_TYPE_PHY_SKU: PHY SKU section + * @NVM_MAX_NUM_SECTIONS: number of sections + */ +enum iwl_nvm_section_type { NVM_SECTION_TYPE_SW = 1, NVM_SECTION_TYPE_REGULATORY = 3, NVM_SECTION_TYPE_CALIBRATION = 4, @@ -467,10 +983,10 @@ enum { }; /** - * struct iwl_nvm_access_cmd_ver2 - Request the device to send an NVM section - * @op_code: 0 - read, 1 - write - * @target: NVM_ACCESS_TARGET_* - * @type: NVM_SECTION_TYPE_* + * struct iwl_nvm_access_cmd - Request the device to send an NVM section + * @op_code: &enum iwl_nvm_access_op + * @target: &enum iwl_nvm_access_target + * @type: &enum iwl_nvm_section_type * @offset: offset in bytes into the section * @length: in bytes, to read/write * @data: if write operation, the data to write. On read its empty @@ -486,7 +1002,7 @@ struct iwl_nvm_access_cmd { #define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ -/* +/** * struct iwl_fw_paging_cmd - paging layout * * (FW_PAGING_BLOCK_CMD = 0x4f) @@ -497,17 +1013,13 @@ struct iwl_nvm_access_cmd { * @block_size: the block size in powers of 2 * @block_num: number of blocks specified in the command. * @device_phy_addr: virtual addresses from device side - * 32 bit address for API version 1, 64 bit address for API version 2. -*/ + */ struct iwl_fw_paging_cmd { __le32 flags; __le32 block_size; __le32 block_num; - union { - __le32 addr32[NUM_OF_FW_PAGING_BLOCKS]; - __le64 addr64[NUM_OF_FW_PAGING_BLOCKS]; - } device_phy_addr; -} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_2 */ + __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; +} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ /* * Fw items ID's @@ -660,6 +1172,7 @@ enum { * ( REPLY_ERROR = 0x2 ) * @error_type: one of FW_ERR_* * @cmd_id: the command ID for which the error occured + * @reserved1: reserved * @bad_cmd_seq_num: sequence number of the erroneous command * @error_service: which service created the error, applicable only if * error_type = 2, otherwise 0 @@ -679,12 +1192,21 @@ struct iwl_error_resp { #define MAX_MACS_IN_BINDING (3) #define MAX_BINDINGS (4) -/* Used to extract ID and color from the context dword */ -#define FW_CTXT_ID_POS (0) -#define FW_CTXT_ID_MSK (0xff << FW_CTXT_ID_POS) -#define FW_CTXT_COLOR_POS (8) -#define FW_CTXT_COLOR_MSK (0xff << FW_CTXT_COLOR_POS) -#define FW_CTXT_INVALID (0xffffffff) +/** + * enum iwl_mvm_id_and_color - ID and color fields in context dword + * @FW_CTXT_ID_POS: position of the ID + * @FW_CTXT_ID_MSK: mask of the ID + * @FW_CTXT_COLOR_POS: position of the color + * @FW_CTXT_COLOR_MSK: mask of the color + * @FW_CTXT_INVALID: value used to indicate unused/invalid + */ +enum iwl_mvm_id_and_color { + FW_CTXT_ID_POS = 0, + FW_CTXT_ID_MSK = 0xff << FW_CTXT_ID_POS, + FW_CTXT_COLOR_POS = 8, + FW_CTXT_COLOR_MSK = 0xff << FW_CTXT_COLOR_POS, + FW_CTXT_INVALID = 0xffffffff, +}; #define FW_CMD_ID_AND_COLOR(_id, _color) ((_id << FW_CTXT_ID_POS) |\ (_color << FW_CTXT_COLOR_POS)) @@ -832,7 +1354,8 @@ enum { #define TE_V2_PLACEMENT_POS 12 #define TE_V2_ABSENCE_POS 15 -/* Time event policy values +/** + * enum iwl_time_event_policy - Time event policy values * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment @@ -847,12 +1370,13 @@ enum { * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. + * @T2_V2_START_IMMEDIATELY: start time event immediately * @TE_V2_DEP_OTHER: depends on another time event * @TE_V2_DEP_TSF: depends on a specific time * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC * @TE_V2_ABSENCE: are we present or absent during the Time Event. */ -enum { +enum iwl_time_event_policy { TE_V2_DEFAULT_POLICY = 0x0, /* notifications (event start/stop, fragment start/stop) */ @@ -867,8 +1391,6 @@ enum { TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), T2_V2_START_IMMEDIATELY = BIT(11), - TE_V2_NOTIF_MSK = 0xff, - /* placement characteristics */ TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), TE_V2_DEP_TSF = BIT(TE_V2_PLACEMENT_POS + 1), @@ -879,12 +1401,13 @@ enum { }; /** - * struct iwl_time_event_cmd_api - configuring Time Events + * struct iwl_time_event_cmd - configuring Time Events * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also * with version 1. determined by IWL_UCODE_TLV_FLAGS) * ( TIME_EVENT_CMD = 0x29 ) - * @id_and_color: ID and color of the relevant MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @id_and_color: ID and color of the relevant MAC, + * &enum iwl_mvm_id_and_color + * @action: action to perform, one of &enum iwl_phy_ctxt_action * @id: this field has two meanings, depending on the action: * If the action is ADD, then it means the type of event to add. * For all other actions it is the unique event ID assigned when the @@ -900,7 +1423,8 @@ enum { * on event and/or fragment start and/or end * using one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF * TE_EVENT_SOCIOPATHIC - * using TE_ABSENCE and using TE_NOTIF_* + * using TE_ABSENCE and using TE_NOTIF_*, + * &enum iwl_time_event_policy */ struct iwl_time_event_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ @@ -923,7 +1447,8 @@ struct iwl_time_event_cmd { * @status: bit 0 indicates success, all others specify errors * @id: the Time Event type * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE - * @id_and_color: ID and color of the relevant MAC + * @id_and_color: ID and color of the relevant MAC, + * &enum iwl_mvm_id_and_color */ struct iwl_time_event_resp { __le32 status; @@ -939,7 +1464,7 @@ struct iwl_time_event_resp { * @session_id: session's unique id * @unique_id: unique id of the Time Event itself * @id_and_color: ID and color of the relevant MAC - * @action: one of TE_NOTIF_START or TE_NOTIF_END + * @action: &enum iwl_time_event_policy * @status: true if scheduled, false otherwise (not executed) */ struct iwl_time_event_notif { @@ -955,12 +1480,35 @@ struct iwl_time_event_notif { /* Bindings and Time Quota */ /** + * struct iwl_binding_cmd_v1 - configuring bindings + * ( BINDING_CONTEXT_CMD = 0x2b ) + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_mvm_id_and_color + * @action: action to perform, one of FW_CTXT_ACTION_* + * @macs: array of MAC id and colors which belong to the binding, + * &enum iwl_mvm_id_and_color + * @phy: PHY id and color which belongs to the binding, + * &enum iwl_mvm_id_and_color + */ +struct iwl_binding_cmd_v1 { + /* COMMON_INDEX_HDR_API_S_VER_1 */ + __le32 id_and_color; + __le32 action; + /* BINDING_DATA_API_S_VER_1 */ + __le32 macs[MAX_MACS_IN_BINDING]; + __le32 phy; +} __packed; /* BINDING_CMD_API_S_VER_1 */ + +/** * struct iwl_binding_cmd - configuring bindings * ( BINDING_CONTEXT_CMD = 0x2b ) - * @id_and_color: ID and color of the relevant Binding + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_mvm_id_and_color * @action: action to perform, one of FW_CTXT_ACTION_* * @macs: array of MAC id and colors which belong to the binding + * &enum iwl_mvm_id_and_color * @phy: PHY id and color which belongs to the binding + * &enum iwl_mvm_id_and_color * @lmac_id: the lmac id the binding belongs to */ struct iwl_binding_cmd { @@ -970,11 +1518,10 @@ struct iwl_binding_cmd { /* BINDING_DATA_API_S_VER_1 */ __le32 macs[MAX_MACS_IN_BINDING]; __le32 phy; - /* BINDING_CMD_API_S_VER_1 */ __le32 lmac_id; } __packed; /* BINDING_CMD_API_S_VER_2 */ -#define IWL_BINDING_CMD_SIZE_V1 offsetof(struct iwl_binding_cmd, lmac_id) +#define IWL_BINDING_CMD_SIZE_V1 sizeof(struct iwl_binding_cmd_v1) #define IWL_LMAC_24G_INDEX 0 #define IWL_LMAC_5G_INDEX 1 @@ -983,7 +1530,8 @@ struct iwl_binding_cmd { /** * struct iwl_time_quota_data - configuration of time quota per binding - * @id_and_color: ID and color of the relevant Binding + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_mvm_id_and_color * @quota: absolute time quota in TU. The scheduler will try to divide the * remainig quota (after Time Events) according to this quota. * @max_duration: max uninterrupted context duration in TU @@ -1087,7 +1635,7 @@ struct iwl_fw_channel_info { * @apply_time: 0 means immediate apply and context switch. * other value means apply new params after X usecs * @tx_param_color: ??? - * @channel_info: + * @ci: channel info * @txchain_info: ??? * @rxchain_info: ??? * @acquisition_data: ??? @@ -1176,9 +1724,9 @@ struct iwl_hs20_roc_res { /** * struct iwl_radio_version_notif - information on the radio version * ( RADIO_VERSION_NOTIFICATION = 0x68 ) - * @radio_flavor: - * @radio_step: - * @radio_dash: + * @radio_flavor: radio flavor + * @radio_step: radio version step + * @radio_dash: radio version dash */ struct iwl_radio_version_notif { __le32 radio_flavor; @@ -1212,8 +1760,8 @@ struct iwl_card_state_notif { * @consec_missed_beacons_since_last_rx: number of consecutive missed * beacons since last RX. * @consec_missed_beacons: number of consecutive missed beacons - * @num_expected_beacons: - * @num_recvd_beacons: + * @num_expected_beacons: number of expected beacons + * @num_recvd_beacons: number of received beacons */ struct iwl_missed_beacons_notif { __le32 mac_id; @@ -1260,19 +1808,6 @@ struct iwl_mfu_assert_dump_notif { __le32 data[0]; } __packed; /*MFU_DUMP_ASSERT_API_S_VER_1*/ -/** - * struct iwl_set_calib_default_cmd - set default value for calibration. - * ( SET_CALIB_DEFAULT_CMD = 0x8e ) - * @calib_index: the calibration to set value for - * @length: of data - * @data: the value to set for the calibration result - */ -struct iwl_set_calib_default_cmd { - __le16 calib_index; - __le16 length; - u8 data[0]; -} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ - #define MAX_PORT_ID_NUM 2 #define MAX_MCAST_FILTERING_ADDRESSES 256 @@ -1286,6 +1821,7 @@ struct iwl_set_calib_default_cmd { * @count: Number of MAC addresses in the array * @pass_all: Set 1 to pass all multicast packets. * @bssid: current association BSSID. + * @reserved: reserved * @addr_list: Place holder for array of MAC addresses. * IMPORTANT: add padding if necessary to ensure DWORD alignment. */ @@ -1317,7 +1853,8 @@ enum iwl_mvm_bcast_filter_attr_offset { * struct iwl_fw_bcast_filter_attr - broadcast filter attribute * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset. * @offset: starting offset of this pattern. - * @val: value to match - big endian (MSB is the first + * @reserved1: reserved + * @val: value to match - big endian (MSB is the first * byte to match from offset pos). * @mask: mask to match (big endian). */ @@ -1343,6 +1880,7 @@ enum iwl_mvm_bcast_filter_frame_type { * struct iwl_fw_bcast_filter - broadcast filter * @discard: discard frame (1) or let it pass (0). * @frame_type: &enum iwl_mvm_bcast_filter_frame_type. + * @reserved1: reserved * @num_attrs: number of valid attributes in this filter. * @attrs: attributes of this filter. a filter is considered matched * only when all its attributes are matched (i.e. AND relationship) @@ -1378,6 +1916,7 @@ struct iwl_ba_window_status_notif { /** * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration. * @default_discard: default action for this mac (discard (1) / pass (0)). + * @reserved1: reserved * @attached_filters: bitmap of relevant filters for this mac. */ struct iwl_fw_bcast_mac { @@ -1391,6 +1930,7 @@ struct iwl_fw_bcast_mac { * @disable: enable (0) / disable (1) * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS) * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER) + * @reserved1: reserved * @filters: broadcast filters * @macs: broadcast filtering configuration per-mac */ @@ -1428,8 +1968,8 @@ enum iwl_mvm_marker_id { * @metadata: additional meta data that will be written to the unsiffer log */ struct iwl_mvm_marker { - u8 dwLen; - u8 markerId; + u8 dw_len; + u8 marker_id; __le16 reserved; __le64 timestamp; __le32 metadata[0]; @@ -1539,8 +2079,8 @@ enum iwl_sf_scenario { #define SF_CFG_DUMMY_NOTIF_OFF BIT(16) /** - * Smart Fifo configuration command. - * @state: smart fifo state, types listed in enum %iwl_sf_sate. + * struct iwl_sf_cfg_cmd - Smart Fifo configuration command. + * @state: smart fifo state, types listed in &enum iwl_sf_state. * @watermark: Minimum allowed availabe free space in RXF for transient state. * @long_delay_timeouts: aging and idle timer values for each scenario * in long delay state. @@ -1590,11 +2130,11 @@ struct iwl_mcc_update_cmd { u8 source_id; u8 reserved; __le32 key; - __le32 reserved2[5]; + u8 reserved2[20]; } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ /** - * iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. + * struct iwl_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. @@ -1617,7 +2157,7 @@ struct iwl_mcc_update_resp_v1 { } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ /** - * iwl_mcc_update_resp - response to MCC_UPDATE_CMD. + * struct iwl_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. @@ -1659,7 +2199,7 @@ struct iwl_mcc_update_resp { * @reserved1: reserved for alignment */ struct iwl_mcc_chub_notif { - u16 mcc; + __le16 mcc; u8 source_id; u8 reserved1; } __packed; /* LAR_MCC_NOTIFY_S */ @@ -1699,10 +2239,10 @@ enum iwl_dts_measurement_flags { }; /** - * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements + * struct iwl_dts_measurement_cmd - request DTS temp and/or voltage measurements * - * @flags: indicates which measurements we want as specified in &enum - * iwl_dts_measurement_flags + * @flags: indicates which measurements we want as specified in + * &enum iwl_dts_measurement_flags */ struct iwl_dts_measurement_cmd { __le32 flags; @@ -1733,7 +2273,7 @@ enum iwl_dts_control_measurement_mode { * @DTS_USE_CHAIN_A: chain A * @DTS_USE_CHAIN_B: chain B * @DTS_USE_CHAIN_C: chain C -* @XTAL_TEMPERATURE - read temperature from xtal +* @XTAL_TEMPERATURE: read temperature from xtal */ enum iwl_dts_used { DTS_USE_TOP = 0, @@ -1754,7 +2294,7 @@ enum iwl_dts_bit_mode { }; /** - * iwl_ext_dts_measurement_cmd - request extended DTS temperature measurements + * struct iwl_ext_dts_measurement_cmd - request extended DTS temp measurements * @control_mode: see &enum iwl_dts_control_measurement_mode * @temperature: used when over write DTS mode is selected * @sensor: set temperature sensor to use. See &enum iwl_dts_used @@ -1810,7 +2350,7 @@ struct ct_kill_notif { * enum ctdp_cmd_operation - CTDP command operations * @CTDP_CMD_OPERATION_START: update the current budget * @CTDP_CMD_OPERATION_STOP: stop ctdp -* @CTDP_CMD_OPERATION_REPORT: get the avgerage budget +* @CTDP_CMD_OPERATION_REPORT: get the average budget */ enum iwl_mvm_ctdp_cmd_operation { CTDP_CMD_OPERATION_START = 0x1, @@ -1834,7 +2374,7 @@ struct iwl_mvm_ctdp_cmd { #define IWL_MAX_DTS_TRIPS 8 /** - * struct iwl_temp_report_ths_cmd - set temperature thresholds + * struct temp_report_ths_cmd - set temperature thresholds * * @num_temps: number of temperature thresholds passed * @thresholds: array with the thresholds to be configured @@ -1856,7 +2396,7 @@ enum iwl_tdls_channel_switch_type { }; /* TDLS_STA_CHANNEL_SWITCH_CMD_TYPE_API_E_VER_1 */ /** - * Switch timing sub-element in a TDLS channel-switch command + * struct iwl_tdls_channel_switch_timing - Switch timing in TDLS channel-switch * @frame_timestamp: GP2 timestamp of channel-switch request/response packet * received from peer * @max_offchan_duration: What amount of microseconds out of a DTIM is given @@ -1864,7 +2404,7 @@ enum iwl_tdls_channel_switch_type { * 200TU and the TDLS peer is to be given 25% of the time, the value * given will be 50TU, or 50 * 1024 if translated into microseconds. * @switch_time: switch time the peer sent in its channel switch timing IE - * @switch_timout: switch timeout the peer sent in its channel switch timing IE + * @switch_timeout: switch timeout the peer sent in its channel switch timing IE */ struct iwl_tdls_channel_switch_timing { __le32 frame_timestamp; /* GP2 time of peer packet Rx */ @@ -1876,7 +2416,7 @@ struct iwl_tdls_channel_switch_timing { #define IWL_TDLS_CH_SW_FRAME_MAX_SIZE 200 /** - * TDLS channel switch frame template + * struct iwl_tdls_channel_switch_frame - TDLS channel switch frame template * * A template representing a TDLS channel-switch request or response frame * @@ -1891,7 +2431,7 @@ struct iwl_tdls_channel_switch_frame { } __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ /** - * TDLS channel switch command + * struct iwl_tdls_channel_switch_cmd - TDLS channel switch command * * The command is sent to initiate a channel switch and also in response to * incoming TDLS channel-switch request/response packets from remote peers. @@ -1911,7 +2451,7 @@ struct iwl_tdls_channel_switch_cmd { } __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */ /** - * TDLS channel switch start notification + * struct iwl_tdls_channel_switch_notif - TDLS channel switch start notification * * @status: non-zero on success * @offchannel_duration: duration given in microseconds @@ -1924,7 +2464,7 @@ struct iwl_tdls_channel_switch_notif { } __packed; /* TDLS_STA_CHANNEL_SWITCH_NTFY_API_S_VER_1 */ /** - * TDLS station info + * struct iwl_tdls_sta_info - TDLS station info * * @sta_id: station id of the TDLS peer * @tx_to_peer_tid: TID reserved vs. the peer for FW based Tx @@ -1939,7 +2479,7 @@ struct iwl_tdls_sta_info { } __packed; /* TDLS_STA_INFO_VER_1 */ /** - * TDLS basic config command + * struct iwl_tdls_config_cmd - TDLS basic config command * * @id_and_color: MAC id and color being configured * @tdls_peer_count: amount of currently connected TDLS peers @@ -1963,7 +2503,7 @@ struct iwl_tdls_config_cmd { } __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ /** - * TDLS per-station config information from FW + * struct iwl_tdls_config_sta_info_res - TDLS per-station config information * * @sta_id: station id of the TDLS peer * @tx_to_peer_last_seq: last sequence number used by FW during FW-based Tx to @@ -1975,7 +2515,7 @@ struct iwl_tdls_config_sta_info_res { } __packed; /* TDLS_STA_INFO_RSP_VER_1 */ /** - * TDLS config information from FW + * struct iwl_tdls_config_res - TDLS config information from FW * * @tx_to_ap_last_seq: last sequence number used by FW during FW-based Tx to AP * @sta_info: per-station TDLS config information @@ -1991,7 +2531,7 @@ struct iwl_tdls_config_res { #define TX_FIFO_INTERNAL_MAX_NUM 6 /** - * Shared memory configuration information from the FW + * struct iwl_shared_mem_cfg_v2 - Shared memory configuration information * * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not * accessible) @@ -2013,7 +2553,7 @@ struct iwl_tdls_config_res { * NOTE: on firmware that don't have IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG * set, the last 3 members don't exist. */ -struct iwl_shared_mem_cfg_v1 { +struct iwl_shared_mem_cfg_v2 { __le32 shared_mem_addr; __le32 shared_mem_size; __le32 sample_buff_addr; @@ -2045,7 +2585,7 @@ struct iwl_shared_mem_lmac_cfg { } __packed; /* SHARED_MEM_ALLOC_LMAC_API_S_VER_1 */ /** - * Shared memory configuration information from the FW + * struct iwl_shared_mem_cfg - Shared memory configuration information * * @shared_mem_addr: shared memory address * @shared_mem_size: shared memory size @@ -2073,8 +2613,9 @@ struct iwl_shared_mem_cfg { } __packed; /* SHARED_MEM_ALLOC_API_S_VER_3 */ /** - * VHT MU-MIMO group configuration + * struct iwl_mu_group_mgmt_cmd - VHT MU-MIMO group configuration * + * @reserved: reserved * @membership_status: a bitmap of MU groups * @user_position:the position of station in a group. If the station is in the * group then bits (group * 2) is the position -1 @@ -2100,7 +2641,7 @@ struct iwl_mu_group_mgmt_notif { #define MAX_STORED_BEACON_SIZE 600 /** - * Stored beacon notification + * struct iwl_stored_beacon_notif - Stored beacon notification * * @system_time: system time on air rise * @tsf: TSF on air rise @@ -2109,6 +2650,7 @@ struct iwl_mu_group_mgmt_notif { * @channel: channel this beacon was received on * @rates: rate in ucode internal format * @byte_count: frame's byte count + * @data: beacon data, length in @byte_count */ struct iwl_stored_beacon_notif { __le32 system_time; @@ -2135,8 +2677,8 @@ enum iwl_lqm_status { }; /** - * Link Quality Measurement command - * @cmd_operatrion: command operation to be performed (start or stop) + * struct iwl_link_qual_msrmnt_cmd - Link Quality Measurement command + * @cmd_operation: command operation to be performed (start or stop) * as defined above. * @mac_id: MAC ID the measurement applies to. * @measurement_time: time of the total measurement to be performed, in uSec. @@ -2150,7 +2692,7 @@ struct iwl_link_qual_msrmnt_cmd { } __packed /* LQM_CMD_API_S_VER_1 */; /** - * Link Quality Measurement notification + * struct iwl_link_qual_msrmnt_notif - Link Quality Measurement notification * * @frequent_stations_air_time: an array containing the total air time * (in uSec) used by the most frequently transmitting stations. @@ -2174,11 +2716,11 @@ struct iwl_link_qual_msrmnt_notif { __le32 tx_frame_dropped; __le32 mac_id; __le32 status; - __le32 reserved[3]; + u8 reserved[12]; } __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */ /** - * Channel switch NOA notification + * struct iwl_channel_switch_noa_notif - Channel switch NOA notification * * @id_and_color: ID and color of the MAC */ @@ -2232,6 +2774,7 @@ struct iwl_dbg_mem_access_rsp { /** * struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed + * @reserved: reserved */ struct iwl_nvm_access_complete_cmd { __le32 reserved; @@ -2259,4 +2802,89 @@ struct iwl_init_extended_cfg_cmd { __le32 init_flags; } __packed; /* INIT_EXTENDED_CFG_CMD_API_S_VER_1 */ +/* + * struct iwl_nvm_get_info - request to get NVM data + */ +struct iwl_nvm_get_info { + __le32 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_general - general NVM data + * @flags: 1 - empty, 0 - valid + * @nvm_version: nvm version + * @board_type: board type + * @reserved: reserved + */ +struct iwl_nvm_get_info_general { + __le32 flags; + __le16 nvm_version; + u8 board_type; + u8 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_sku - mac information + * @enable_24g: band 2.4G enabled + * @enable_5g: band 5G enabled + * @enable_11n: 11n enabled + * @enable_11ac: 11ac enabled + * @mimo_disable: MIMO enabled + * @ext_crypto: Extended crypto enabled + */ +struct iwl_nvm_get_info_sku { + __le32 enable_24g; + __le32 enable_5g; + __le32 enable_11n; + __le32 enable_11ac; + __le32 mimo_disable; + __le32 ext_crypto; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_MAC_SKU_SECTION_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_phy - phy information + * @tx_chains: BIT 0 chain A, BIT 1 chain B + * @rx_chains: BIT 0 chain A, BIT 1 chain B + */ +struct iwl_nvm_get_info_phy { + __le32 tx_chains; + __le32 rx_chains; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ + +#define IWL_NUM_CHANNELS (51) + +/** + * struct iwl_nvm_get_info_regulatory - regulatory information + * @lar_enabled: is LAR enabled + * @channel_profile: regulatory data of this channel + * @reserved: reserved + */ +struct iwl_nvm_get_info_regulatory { + __le32 lar_enabled; + __le16 channel_profile[IWL_NUM_CHANNELS]; + __le16 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_rsp - response to get NVM data + * @general: general NVM data + * @mac_sku: data relating to MAC sku + * @phy_sku: data relating to PHY sku + * @regulatory: regulatory data + */ +struct iwl_nvm_get_info_rsp { + struct iwl_nvm_get_info_general general; + struct iwl_nvm_get_info_sku mac_sku; + struct iwl_nvm_get_info_phy phy_sku; + struct iwl_nvm_get_info_regulatory regulatory; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_1 */ + +/** + * struct iwl_mvm_antenna_coupling_notif - antenna coupling notification + * @isolation: antenna isolation value + */ +struct iwl_mvm_antenna_coupling_notif { + __le32 isolation; +} __packed; + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index c8712e6eea74..1602b360353c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -319,10 +319,8 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm) { - if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert) - return; - - kfree(mvm->fw_dump_desc); + if (mvm->fw_dump_desc != &iwl_mvm_dump_desc_assert) + kfree(mvm->fw_dump_desc); mvm->fw_dump_desc = NULL; } @@ -640,18 +638,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } /* Make room for PRPH registers */ - for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); i++) { - /* The range includes both boundaries */ - int num_bytes_in_chunk = - iwl_prph_dump_addr_comm[i].end - - iwl_prph_dump_addr_comm[i].start + 4; - - prph_len += sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; + if (!mvm->trans->cfg->gen2) { + for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); + i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = + iwl_prph_dump_addr_comm[i].end - + iwl_prph_dump_addr_comm[i].start + 4; + + prph_len += sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } } - if (mvm->cfg->mq_rx_supported) { + if (!mvm->trans->cfg->gen2 && mvm->cfg->mq_rx_supported) { for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) { /* The range includes both boundaries */ @@ -691,7 +692,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } /* Make room for fw's virtual image pages, if it exists */ - if (mvm->fw->img[mvm->cur_ucode].paging_mem_size && + if (!mvm->trans->cfg->gen2 && + mvm->fw->img[mvm->cur_ucode].paging_mem_size && mvm->fw_paging_db[0].fw_paging_block) file_len += mvm->num_of_paging_blk * (sizeof(*dump_data) + @@ -704,14 +706,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sizeof(*dump_info); } - /* - * In 8000 HW family B-step include the ICCM (which resides separately) - */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + - IWL8260_ICCM_LEN; - if (mvm->fw_dump_desc) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + mvm->fw_dump_desc->len; @@ -836,21 +830,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data = iwl_fw_error_next_data(dump_data); } - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) { - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - dump_data->len = cpu_to_le32(IWL8260_ICCM_LEN + - sizeof(*dump_mem)); - dump_mem = (void *)dump_data->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); - dump_mem->offset = cpu_to_le32(IWL8260_ICCM_OFFSET); - iwl_trans_read_mem_bytes(mvm->trans, IWL8260_ICCM_OFFSET, - dump_mem->data, IWL8260_ICCM_LEN); - dump_data = iwl_fw_error_next_data(dump_data); - } - /* Dump fw's virtual image */ - if (mvm->fw->img[mvm->cur_ucode].paging_mem_size && + if (!mvm->trans->cfg->gen2 && + mvm->fw->img[mvm->cur_ucode].paging_mem_size && mvm->fw_paging_db[0].fw_paging_block) { for (i = 1; i < mvm->num_of_paging_blk + 1; i++) { struct iwl_fw_error_dump_paging *paging; @@ -931,6 +913,10 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, if (trigger) delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); + if (WARN(mvm->trans->state == IWL_TRANS_NO_FW, + "Can't collect dbg data when FW isn't alive\n")) + return -EIO; + if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status)) return -EBUSY; @@ -943,7 +929,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, mvm->fw_dump_desc = desc; mvm->fw_dump_trig = trigger; - queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); + schedule_delayed_work(&mvm->fw_dump_wk, delay); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h index e9f1be9da7d4..4a5287a0c617 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h @@ -65,8 +65,8 @@ #ifndef __mvm_fw_dbg_h__ #define __mvm_fw_dbg_h__ -#include "iwl-fw-file.h" -#include "iwl-fw-error-dump.h" +#include "fw/file.h" +#include "fw/error-dump.h" #include "mvm.h" void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index e6c9528eeeda..79e7a7a285dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -70,7 +70,7 @@ #include "iwl-trans.h" #include "iwl-op-mode.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-debug.h" #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */ #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */ @@ -385,40 +385,28 @@ static int iwl_save_fw_paging(struct iwl_mvm *mvm, static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) { struct iwl_fw_paging_cmd paging_cmd = { - .flags = - cpu_to_le32(PAGING_CMD_IS_SECURED | - PAGING_CMD_IS_ENABLED | - (mvm->num_of_pages_in_last_blk << - PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), + .flags = cpu_to_le32(PAGING_CMD_IS_SECURED | + PAGING_CMD_IS_ENABLED | + (mvm->num_of_pages_in_last_blk << + PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), .block_num = cpu_to_le32(mvm->num_of_paging_blk), }; - int blk_idx, size = sizeof(paging_cmd); - - /* A bit hard coded - but this is the old API and will be deprecated */ - if (!iwl_mvm_has_new_tx_api(mvm)) - size -= NUM_OF_FW_PAGING_BLOCKS * 4; + int blk_idx; /* loop for for all paging blocks + CSS block */ for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { dma_addr_t addr = mvm->fw_paging_db[blk_idx].fw_paging_phys; + __le32 phy_addr; addr = addr >> PAGE_2_EXP_SIZE; - - if (iwl_mvm_has_new_tx_api(mvm)) { - __le64 phy_addr = cpu_to_le64(addr); - - paging_cmd.device_phy_addr.addr64[blk_idx] = phy_addr; - } else { - __le32 phy_addr = cpu_to_le32(addr); - - paging_cmd.device_phy_addr.addr32[blk_idx] = phy_addr; - } + phy_addr = cpu_to_le32(addr); + paging_cmd.device_phy_addr[blk_idx] = phy_addr; } return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(FW_PAGING_BLOCK_CMD, IWL_ALWAYS_LONG_GROUP, 0), - 0, size, &paging_cmd); + 0, sizeof(paging_cmd), &paging_cmd); } /* @@ -619,7 +607,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, if (WARN_ON(!fw)) return -EINVAL; mvm->cur_ucode = ucode_type; - mvm->ucode_loaded = false; + clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, alive_cmd, ARRAY_SIZE(alive_cmd), @@ -641,12 +629,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, if (ret) { struct iwl_trans *trans = mvm->trans; - if (trans->cfg->gen2) + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", iwl_read_prph(trans, UMAG_SB_CPU_1_STATUS), iwl_read_prph(trans, UMAG_SB_CPU_2_STATUS)); - else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", iwl_read_prph(trans, SB_CPU_1_STATUS), @@ -693,7 +681,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, for (i = 0; i < IEEE80211_MAX_QUEUES; i++) atomic_set(&mvm->mac80211_queue_stop_count[i], 0); - mvm->ucode_loaded = true; + set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); return 0; } @@ -738,9 +726,13 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto error; } - /* Read the NVM only at driver load time, no need to do this twice */ - if (read_nvm) { - /* Read nvm */ + /* Load NVM to NIC if needed */ + if (mvm->nvm_file_name) { + iwl_mvm_read_external_nvm(mvm); + iwl_mvm_load_nvm_to_nic(mvm); + } + + if (IWL_MVM_PARSE_NVM && read_nvm) { ret = iwl_nvm_init(mvm, true); if (ret) { IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); @@ -748,14 +740,6 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } } - /* In case we read the NVM from external file, load it to the NIC */ - if (mvm->nvm_file_name) - iwl_mvm_load_nvm_to_nic(mvm); - - ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); - if (WARN_ON(ret)) - goto error; - ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_ACCESS_COMPLETE), 0, sizeof(nvm_complete), &nvm_complete); @@ -766,8 +750,21 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } /* We wait for the INIT complete notification */ - return iwl_wait_notification(&mvm->notif_wait, &init_wait, - MVM_UCODE_ALIVE_TIMEOUT); + ret = iwl_wait_notification(&mvm->notif_wait, &init_wait, + MVM_UCODE_ALIVE_TIMEOUT); + if (ret) + return ret; + + /* Read the NVM only at driver load time, no need to do this twice */ + if (!IWL_MVM_PARSE_NVM && read_nvm) { + ret = iwl_mvm_nvm_get_from_fw(mvm); + if (ret) { + IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); + return ret; + } + } + + return 0; error: iwl_remove_notification(&mvm->notif_wait, &init_wait); @@ -824,9 +821,11 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto error; } - ret = iwl_send_bt_init_conf(mvm); - if (ret) - goto error; + if (mvm->cfg->device_family < IWL_DEVICE_FAMILY_8000) { + ret = iwl_mvm_send_bt_init_conf(mvm); + if (ret) + goto error; + } /* Read the NVM only at driver load time, no need to do this twice */ if (read_nvm) { @@ -941,7 +940,7 @@ static void iwl_mvm_parse_shared_mem_a000(struct iwl_mvm *mvm, static void iwl_mvm_parse_shared_mem(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { - struct iwl_shared_mem_cfg_v1 *mem_cfg = (void *)pkt->data; + struct iwl_shared_mem_cfg_v2 *mem_cfg = (void *)pkt->data; int i; mvm->smem_cfg.num_lmacs = 1; @@ -1231,15 +1230,15 @@ out_free: return ret; } -static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm, - struct iwl_mvm_geo_table *geo_table) +static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) { union acpi_object *wifi_pkg; acpi_handle root_handle; acpi_handle handle; struct acpi_buffer wgds = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; - int i, ret; + int i, j, ret; + int idx = 1; root_handle = ACPI_HANDLE(mvm->dev); if (!root_handle) { @@ -1270,15 +1269,17 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm, goto out_free; } - for (i = 0; i < ACPI_WGDS_WIFI_DATA_SIZE; i++) { - union acpi_object *entry; + for (i = 0; i < IWL_NUM_GEO_PROFILES; i++) { + for (j = 0; j < IWL_MVM_GEO_TABLE_SIZE; j++) { + union acpi_object *entry; - entry = &wifi_pkg->package.elements[i + 1]; - if ((entry->type != ACPI_TYPE_INTEGER) || - (entry->integer.value > U8_MAX)) - return -EINVAL; + entry = &wifi_pkg->package.elements[idx++]; + if ((entry->type != ACPI_TYPE_INTEGER) || + (entry->integer.value > U8_MAX)) + return -EINVAL; - geo_table->values[i] = entry->integer.value; + mvm->geo_profiles[i].values[j] = entry->integer.value; + } } ret = 0; out_free: @@ -1339,16 +1340,47 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } +int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) +{ + struct iwl_geo_tx_power_profiles_resp *resp; + int ret; + + struct iwl_geo_tx_power_profiles_cmd geo_cmd = { + .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE), + }; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT), + .len = { sizeof(geo_cmd), }, + .flags = CMD_WANT_SKB, + .data = { &geo_cmd }, + }; + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret); + return ret; + } + + resp = (void *)cmd.resp_pkt->data; + ret = le32_to_cpu(resp->profile_idx); + if (WARN_ON(ret > IWL_NUM_GEO_PROFILES)) { + ret = -EIO; + IWL_WARN(mvm, "Invalid geographic profile idx (%d)\n", ret); + } + + iwl_free_resp(&cmd); + return ret; +} + static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) { - struct iwl_mvm_geo_table geo_table; struct iwl_geo_tx_power_profiles_cmd cmd = { .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), }; - int ret, i, j, idx; + int ret, i, j; u16 cmd_wide_id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT); - ret = iwl_mvm_sar_get_wgds_table(mvm, &geo_table); + ret = iwl_mvm_sar_get_wgds_table(mvm); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "Geo SAR BIOS table invalid or unavailable. (%d)\n", @@ -1369,9 +1401,8 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) for (j = 0; j < ACPI_WGDS_NUM_BANDS; j++) { u8 *value; - idx = i * ACPI_WGDS_NUM_BANDS * ACPI_WGDS_TABLE_SIZE + - j * ACPI_WGDS_TABLE_SIZE; - value = &geo_table.values[idx]; + value = &mvm->geo_profiles[i].values[j * + IWL_GEO_PER_CHAIN_SIZE]; chain[j].max_tx_power = cpu_to_le16(value[0]); chain[j].chain_a = value[1]; chain[j].chain_b = value[2]; @@ -1501,10 +1532,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; - ret = iwl_send_bt_init_conf(mvm); - if (ret) - goto error; - /* Send phy db control command and then phy db calibration*/ if (!iwl_mvm_has_new_tx_api(mvm)) { ret = iwl_send_phy_db_data(mvm->phy_db); @@ -1516,6 +1543,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + ret = iwl_mvm_send_bt_init_conf(mvm); + if (ret) + goto error; + /* Init RSS configuration */ /* TODO - remove a000 disablement when we have RXQ config API */ if (iwl_mvm_has_new_rx_api(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { @@ -1627,7 +1658,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: - iwl_mvm_stop_device(mvm); + if (!iwlmvm_mod_params.init_dbg) + iwl_mvm_stop_device(mvm); return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index 1e51fbe95f7c..3cac4278a5fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -123,14 +123,17 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) return ret; } + mvm->init_status |= IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE; return 0; } void iwl_mvm_leds_exit(struct iwl_mvm *mvm) { - if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE) + if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE || + !(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE)) return; led_classdev_unregister(&mvm->led); kfree(mvm->led.name); + mvm->init_status &= ~IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index fd2fc46e2fe5..dc631b23e189 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -257,7 +257,7 @@ unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, }; if (iwl_mvm_is_dqa_supported(mvm)) - data.used_hw_queues |= BIT(IWL_MVM_DQA_CMD_QUEUE); + data.used_hw_queues |= BIT(IWL_MVM_DQA_GCAST_QUEUE); else data.used_hw_queues |= BIT(IWL_MVM_CMD_QUEUE); @@ -268,6 +268,14 @@ unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, iwl_mvm_iface_hw_queues_iter, &data); + /* + * for DQA, the hw_queue in mac80211 is never really used for + * real traffic (only the few queue IDs covered above), so + * we can reuse the real HW queue IDs the stations use + */ + if (iwl_mvm_is_dqa_supported(mvm)) + return data.used_hw_queues; + /* don't assign the same hw queues as TDLS stations */ ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_mac_sta_hw_queues_iter, @@ -344,7 +352,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, .found_vif = false, }; u32 ac; - int ret, i; + int ret, i, queue_limit; unsigned long used_hw_queues; /* @@ -430,17 +438,29 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, return 0; } + if (iwl_mvm_is_dqa_supported(mvm)) { + /* + * queues in mac80211 almost entirely independent of + * the ones here - no real limit + */ + queue_limit = IEEE80211_MAX_QUEUES; + BUILD_BUG_ON(IEEE80211_MAX_QUEUES > + BITS_PER_BYTE * + sizeof(mvm->hw_queue_to_mac80211[0])); + } else { + /* need to not use too many in this case */ + queue_limit = mvm->first_agg_queue; + } + /* * Find available queues, and allocate them to the ACs. When in * DQA-mode they aren't really used, and this is done only so the * mac80211 ieee80211_check_queues() function won't fail */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - u8 queue = find_first_zero_bit(&used_hw_queues, - mvm->first_agg_queue); + u8 queue = find_first_zero_bit(&used_hw_queues, queue_limit); - if (!iwl_mvm_is_dqa_supported(mvm) && - queue >= mvm->first_agg_queue) { + if (queue >= queue_limit) { IWL_ERR(mvm, "Failed to allocate queue\n"); ret = -EIO; goto exit_fail; @@ -846,6 +866,8 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, cpu_to_le64(vif->bss_conf.sync_tsf + dtim_offs); ctxt_sta->dtim_time = cpu_to_le32(vif->bss_conf.sync_device_ts + dtim_offs); + ctxt_sta->assoc_beacon_arrive_time = + cpu_to_le32(vif->bss_conf.sync_device_ts); IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n", le64_to_cpu(ctxt_sta->dtim_tsf), @@ -1457,6 +1479,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, beacon_notify_hdr = &beacon->beacon_notify_hdr; mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); + mvm->ibss_manager = beacon->ibss_mgr_status != 0; agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr); status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK; @@ -1596,7 +1619,7 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, rx_status.band); /* copy the data */ - memcpy(skb_put(skb, size), sb->data, size); + skb_put_data(skb, sb->data, size); memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); /* pass it as regular rx to mac80211 */ @@ -1632,9 +1655,9 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n"); - queue_delayed_work(system_wq, &mvm->cs_tx_unblock_dwork, - msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * - csa_vif->bss_conf.beacon_int)); + schedule_delayed_work(&mvm->cs_tx_unblock_dwork, + msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * + csa_vif->bss_conf.beacon_int)); ieee80211_csa_finish(csa_vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a67aa1f5a51c..bcde1ba0f1c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -84,7 +84,7 @@ #include "iwl-eeprom-parse.h" #include "iwl-phy-db.h" #include "testmode.h" -#include "iwl-fw-error-dump.h" +#include "fw/error-dump.h" #include "iwl-prph.h" #include "iwl-nvm-parse.h" #include "fw-dbg.h" @@ -493,7 +493,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) * firmware will interpret some mgmt packets, so enabling it * with software crypto isn't safe). */ - if (!iwlwifi_mod_params.sw_crypto) { + if (!iwlwifi_mod_params.swcrypto) { ieee80211_hw_set(hw, MFP_CAPABLE); mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC; @@ -687,7 +687,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) WIPHY_WOWLAN_EAP_IDENTITY_REQ | WIPHY_WOWLAN_RFKILL_RELEASE | WIPHY_WOWLAN_NET_DETECT; - if (!iwlwifi_mod_params.sw_crypto) + if (!iwlwifi_mod_params.swcrypto) mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE | WIPHY_WOWLAN_4WAY_HANDSHAKE; @@ -735,6 +735,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ret = ieee80211_register_hw(mvm->hw); if (ret) iwl_mvm_leds_exit(mvm); + mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE; if (mvm->cfg->vht_mu_mimo_supported) wiphy_ext_feature_set(hw->wiphy, @@ -1243,6 +1244,17 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) flush_work(&mvm->d0i3_exit_work); flush_work(&mvm->async_handlers_wk); flush_work(&mvm->add_stream_wk); + + /* + * Lock and clear the firmware running bit here already, so that + * new commands coming in elsewhere, e.g. from debugfs, will not + * be able to proceed. This is important here because one of those + * debugfs files causes the fw_dump_wk to be triggered, and if we + * don't stop debugfs accesses before canceling that it could be + * retriggered after we flush it but before we've cleared the bit. + */ + clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); + cancel_delayed_work_sync(&mvm->fw_dump_wk); cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork); cancel_delayed_work_sync(&mvm->scan_timeout_dwork); @@ -1451,7 +1463,7 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, { u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); - if (tfd_msk) { + if (tfd_msk && !iwl_mvm_is_dqa_supported(mvm)) { /* * mac80211 first removes all the stations of the vif and * then removes the vif. When it removes a station it also @@ -1460,6 +1472,8 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, * of these AMPDU sessions are properly closed. * We still need to take care of the shared queues of the vif. * Flush them here. + * For DQA mode there is no need - broacast and multicast queue + * are flushed separately. */ mutex_lock(&mvm->mutex); iwl_mvm_flush_tx_path(mvm, tfd_msk, 0); @@ -1974,14 +1988,32 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false), "Failed to update SF upon disassociation\n"); - /* remove AP station now that the MAC is unassoc */ - ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); - if (ret) - IWL_ERR(mvm, "failed to remove AP station\n"); + /* + * If we get an assert during the connection (after the + * station has been added, but before the vif is set + * to associated), mac80211 will re-add the station and + * then configure the vif. Since the vif is not + * associated, we would remove the station here and + * this would fail the recovery. + */ + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, + &mvm->status)) { + /* + * Remove AP station now that + * the MAC is unassoc + */ + ret = iwl_mvm_rm_sta_id(mvm, vif, + mvmvif->ap_sta_id); + if (ret) + IWL_ERR(mvm, + "failed to remove AP station\n"); + + if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) + mvm->d0i3_ap_sta_id = + IWL_MVM_INVALID_STA; + mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; + } - if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) - mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; - mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; /* remove quota for this interface */ ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) @@ -2381,7 +2413,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, __set_bit(tid_data->txq_id, &txqs); - if (iwl_mvm_tid_queued(tid_data) == 0) + if (iwl_mvm_tid_queued(mvm, tid_data) == 0) continue; __set_bit(tid, &tids); @@ -2856,7 +2888,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, int ret; u8 key_offset; - if (iwlwifi_mod_params.sw_crypto) { + if (iwlwifi_mod_params.swcrypto) { IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -2869,7 +2901,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + if (!iwl_mvm_has_new_tx_api(mvm)) + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; break; case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_BIP_GMAC_128: @@ -2915,8 +2948,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ret = -EOPNOTSUPP; else ret = 0; - key->hw_key_idx = STA_KEY_IDX_INVALID; - break; + + if (key->cipher != WLAN_CIPHER_SUITE_GCMP && + key->cipher != WLAN_CIPHER_SUITE_GCMP_256 && + !iwl_mvm_has_new_tx_api(mvm)) { + key->hw_key_idx = STA_KEY_IDX_INVALID; + break; + } } /* During FW restart, in order to restore the state as it was, @@ -3717,6 +3755,13 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, return ret; } +static int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + return mvm->ibss_manager; +} + static int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) @@ -3988,21 +4033,23 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, /* make sure only TDLS peers or the AP are flushed */ WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls); - msk |= mvmsta->tfd_queue_msk; + if (drop) { + if (iwl_mvm_flush_sta(mvm, mvmsta, false, 0)) + IWL_ERR(mvm, "flush request fail\n"); + } else { + msk |= mvmsta->tfd_queue_msk; + if (iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_wait_sta_queues_empty(mvm, mvmsta); + } } - if (drop) { - if (iwl_mvm_flush_tx_path(mvm, msk, 0)) - IWL_ERR(mvm, "flush request fail\n"); - mutex_unlock(&mvm->mutex); - } else { - mutex_unlock(&mvm->mutex); + mutex_unlock(&mvm->mutex); - /* this can take a while, and we may need/want other operations - * to succeed while doing this, so do it without the mutex held - */ + /* this can take a while, and we may need/want other operations + * to succeed while doing this, so do it without the mutex held + */ + if (!drop && !iwl_mvm_has_new_tx_api(mvm)) iwl_trans_wait_tx_queues_empty(mvm->trans, msk); - } } static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, @@ -4023,7 +4070,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, mutex_lock(&mvm->mutex); - if (mvm->ucode_loaded) { + if (iwl_mvm_firmware_running(mvm)) { ret = iwl_mvm_request_statistics(mvm, false); if (ret) goto out; @@ -4104,11 +4151,11 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const struct ieee80211_event *event) { -#define CHECK_MLME_TRIGGER(_mvm, _trig, _buf, _cnt, _fmt...) \ +#define CHECK_MLME_TRIGGER(_cnt, _fmt...) \ do { \ - if ((_cnt) && --(_cnt)) \ + if ((trig_mlme->_cnt) && --(trig_mlme->_cnt)) \ break; \ - iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt);\ + iwl_mvm_fw_dbg_collect_trig(mvm, trig, _fmt); \ } while (0) struct iwl_fw_dbg_trigger_tlv *trig; @@ -4124,31 +4171,25 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm, if (event->u.mlme.data == ASSOC_EVENT) { if (event->u.mlme.status == MLME_DENIED) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_assoc_denied, + CHECK_MLME_TRIGGER(stop_assoc_denied, "DENIED ASSOC: reason %d", event->u.mlme.reason); else if (event->u.mlme.status == MLME_TIMEOUT) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_assoc_timeout, + CHECK_MLME_TRIGGER(stop_assoc_timeout, "ASSOC TIMEOUT"); } else if (event->u.mlme.data == AUTH_EVENT) { if (event->u.mlme.status == MLME_DENIED) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_auth_denied, + CHECK_MLME_TRIGGER(stop_auth_denied, "DENIED AUTH: reason %d", event->u.mlme.reason); else if (event->u.mlme.status == MLME_TIMEOUT) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_auth_timeout, + CHECK_MLME_TRIGGER(stop_auth_timeout, "AUTH TIMEOUT"); } else if (event->u.mlme.data == DEAUTH_RX_EVENT) { - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_rx_deauth, + CHECK_MLME_TRIGGER(stop_rx_deauth, "DEAUTH RX %d", event->u.mlme.reason); } else if (event->u.mlme.data == DEAUTH_TX_EVENT) { - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_tx_deauth, + CHECK_MLME_TRIGGER(stop_tx_deauth, "DEAUTH TX %d", event->u.mlme.reason); } #undef CHECK_MLME_TRIGGER @@ -4248,11 +4289,13 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, goto out; } - if (notif->sync) + if (notif->sync) { ret = wait_event_timeout(mvm->rx_sync_waitq, - atomic_read(&mvm->queue_sync_counter) == 0, + atomic_read(&mvm->queue_sync_counter) == 0 || + iwl_mvm_is_radio_killed(mvm), HZ); - WARN_ON_ONCE(!ret); + WARN_ON_ONCE(!ret && !iwl_mvm_is_radio_killed(mvm)); + } out: atomic_set(&mvm->queue_sync_counter, 0); @@ -4316,6 +4359,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .join_ibss = iwl_mvm_start_ap_ibss, .leave_ibss = iwl_mvm_stop_ap_ibss, + .tx_last_beacon = iwl_mvm_tx_last_beacon, + .set_tim = iwl_mvm_set_tim, .channel_switch = iwl_mvm_channel_switch, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 52f8d7a6a7dc..eaacfaf37206 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -79,9 +79,9 @@ #include "iwl-op-mode.h" #include "iwl-trans.h" -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-eeprom-parse.h" -#include "iwl-fw-file.h" +#include "fw/file.h" #include "iwl-config.h" #include "sta.h" #include "fw-api.h" @@ -724,14 +724,14 @@ enum iwl_mvm_queue_status { #ifdef CONFIG_ACPI #define IWL_MVM_SAR_TABLE_SIZE 10 #define IWL_MVM_SAR_PROFILE_NUM 4 -#define IWL_MVM_GEO_TABLE_SIZE 18 +#define IWL_MVM_GEO_TABLE_SIZE 6 struct iwl_mvm_sar_profile { bool enabled; u8 table[IWL_MVM_SAR_TABLE_SIZE]; }; -struct iwl_mvm_geo_table { +struct iwl_mvm_geo_profile { u8 values[IWL_MVM_GEO_TABLE_SIZE]; }; #endif @@ -754,6 +754,8 @@ struct iwl_mvm { struct work_struct roc_done_wk; + unsigned long init_status; + unsigned long status; u32 queue_sync_cookie; @@ -765,7 +767,6 @@ struct iwl_mvm { struct iwl_mvm_vif *bf_allowed_vif; enum iwl_ucode_type cur_ucode; - bool ucode_loaded; bool hw_registered; bool calibrating; u32 error_event_table[2]; @@ -779,7 +780,10 @@ struct iwl_mvm { struct iwl_notif_wait_data notif_wait; - struct mvm_statistics_rx rx_stats; + union { + struct mvm_statistics_rx_v3 rx_stats_v3; + struct mvm_statistics_rx rx_stats; + }; struct { u64 rx_time; @@ -788,7 +792,7 @@ struct iwl_mvm { u64 on_time_scan; } radio_stats, accu_radio_stats; - u8 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES]; + u16 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES]; struct { u8 hw_queue_refcount; @@ -920,7 +924,7 @@ struct iwl_mvm { u8 vif_count; /* -1 for always, 0 for never, >0 for that many times */ - s8 restart_fw; + s8 fw_restart; u8 fw_dbg_conf; struct delayed_work fw_dump_wk; const struct iwl_mvm_dump_desc *fw_dump_desc; @@ -1020,6 +1024,9 @@ struct iwl_mvm { /* system time of last beacon (for AP/GO interface) */ u32 ap_last_beacon_gp2; + /* indicates that we transmitted the last beacon */ + bool ibss_manager; + bool lar_regdom_set; enum iwl_mcc_source mcc_src; @@ -1067,6 +1074,7 @@ struct iwl_mvm { struct delayed_work cs_tx_unblock_dwork; #ifdef CONFIG_ACPI struct iwl_mvm_sar_profile sar_profiles[IWL_MVM_SAR_PROFILE_NUM]; + struct iwl_mvm_geo_profile geo_profiles[IWL_NUM_GEO_PROFILES]; #endif }; @@ -1077,6 +1085,18 @@ struct iwl_mvm { #define IWL_MAC80211_GET_MVM(_hw) \ IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) +/** + * enum iwl_mvm_status - MVM status bits + * @IWL_MVM_STATUS_HW_RFKILL: HW RF-kill is asserted + * @IWL_MVM_STATUS_HW_CTKILL: CT-kill is active + * @IWL_MVM_STATUS_ROC_RUNNING: remain-on-channel is running + * @IWL_MVM_STATUS_IN_HW_RESTART: HW restart is active + * @IWL_MVM_STATUS_IN_D0I3: NIC is in D0i3 + * @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running + * @IWL_MVM_STATUS_D3_RECONFIG: D3 reconfiguration is being done + * @IWL_MVM_STATUS_DUMPING_FW_LOG: FW log is being dumped + * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running + */ enum iwl_mvm_status { IWL_MVM_STATUS_HW_RFKILL, IWL_MVM_STATUS_HW_CTKILL, @@ -1086,6 +1106,15 @@ enum iwl_mvm_status { IWL_MVM_STATUS_ROC_AUX_RUNNING, IWL_MVM_STATUS_D3_RECONFIG, IWL_MVM_STATUS_DUMPING_FW_LOG, + IWL_MVM_STATUS_FIRMWARE_RUNNING, +}; + +/* Keep track of completed init configuration */ +enum iwl_mvm_init_status { + IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE = BIT(0), + IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE = BIT(1), + IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE = BIT(2), + IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE = BIT(3), }; static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) @@ -1099,6 +1128,11 @@ static inline bool iwl_mvm_is_radio_hw_killed(struct iwl_mvm *mvm) return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); } +static inline bool iwl_mvm_firmware_running(struct iwl_mvm *mvm) +{ + return test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); +} + /* Must be called with rcu_read_lock() held and it can only be * released when mvmsta is not needed anymore. */ @@ -1188,7 +1222,7 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) * Enable LAR only if it is supported by the FW (TLV) && * enabled in the NVM */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (mvm->cfg->ext_nvm) return nvm_lar && tlv_lar; else return tlv_lar; @@ -1266,14 +1300,19 @@ static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CDB_SUPPORT); } -static inline struct agg_tx_status* -iwl_mvm_get_agg_status(struct iwl_mvm *mvm, - struct iwl_mvm_tx_resp *tx_resp) +static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_NEW_RX_STATS); +} + +static inline struct agg_tx_status * +iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp) { if (iwl_mvm_has_new_tx_api(mvm)) - return &tx_resp->v6.status; + return &((struct iwl_mvm_tx_resp *)tx_resp)->status; else - return &tx_resp->v3.status; + return ((struct iwl_mvm_tx_resp_v3 *)tx_resp)->status; } static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) @@ -1355,6 +1394,10 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status); static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } #endif int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags); +int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags); +int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id, + u16 tids, u32 flags); + void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, @@ -1381,7 +1424,9 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm); /* NVM */ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic); +int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm); int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); +int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm); static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm) { @@ -1644,7 +1689,7 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode); int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); /* BT Coex */ -int iwl_send_bt_init_conf(struct iwl_mvm *mvm); +int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm); void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -1711,7 +1756,7 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) } /* hw scheduler queue config */ -void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, +bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout); int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, @@ -1755,7 +1800,7 @@ static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { if (!iwl_mvm_has_new_tx_api(mvm)) iwl_free_fw_paging(mvm); - mvm->ucode_loaded = false; + clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); mvm->fw_dbg_conf = FW_DBG_INVALID; iwl_trans_stop_device(mvm->trans); } @@ -1854,12 +1899,19 @@ bool iwl_mvm_lqm_active(struct iwl_mvm *mvm); #ifdef CONFIG_ACPI int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); +int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); #else static inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { return -ENOENT; } + +static inline +int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) +{ + return -ENOENT; +} #endif /* CONFIG_ACPI */ #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 283c41df622c..dac7e542a190 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -77,7 +77,7 @@ /* Default NVM size to read */ #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) #define IWL_MAX_NVM_SECTION_SIZE 0x1b58 -#define IWL_MAX_NVM_8000_SECTION_SIZE 0x1ffc +#define IWL_MAX_EXT_NVM_SECTION_SIZE 0x1ffc #define NVM_WRITE_OPCODE 1 #define NVM_READ_OPCODE 0 @@ -118,10 +118,6 @@ static int iwl_nvm_write_chunk(struct iwl_mvm *mvm, u16 section, return ret; pkt = cmd.resp_pkt; - if (!pkt) { - IWL_ERR(mvm, "Error in NVM_ACCESS response\n"); - return -EINVAL; - } /* Extract & check NVM write response */ nvm_resp = (void *)pkt->data; if (le16_to_cpu(nvm_resp->status) != READ_NVM_CHUNK_SUCCEED) { @@ -300,7 +296,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) bool lar_enabled; /* Checking for required sections */ - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!mvm->trans->cfg->ext_nvm) { if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n"); @@ -374,7 +370,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) * * 4. save as "iNVM_xxx.bin" under /lib/firmware */ -static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) +int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) { int ret, section_size; u16 section_id; @@ -391,19 +387,19 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) #define NVM_WORD2_ID(x) (x >> 12) -#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) -#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) +#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8)) +#define EXT_NVM_WORD1_ID(x) ((x) >> 4) #define NVM_HEADER_0 (0x2A504C54) #define NVM_HEADER_1 (0x4E564D2A) #define NVM_HEADER_SIZE (4 * sizeof(u32)) IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); - /* Maximal size depends on HW family and step */ - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + /* Maximal size depends on NVM version */ + if (!mvm->trans->cfg->ext_nvm) max_section_size = IWL_MAX_NVM_SECTION_SIZE; else - max_section_size = IWL_MAX_NVM_8000_SECTION_SIZE; + max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; /* * Obtain NVM image via request_firmware. Since we already used @@ -447,10 +443,9 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) le32_to_cpu(dword_buff[3])); /* nvm file validation, dword_buff[2] holds the file version */ - if ((CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && - le32_to_cpu(dword_buff[2]) < 0xE4A) || - (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP && - le32_to_cpu(dword_buff[2]) >= 0xE4A)) { + if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && + le32_to_cpu(dword_buff[2]) < 0xE4A) { ret = -EFAULT; goto out; } @@ -472,14 +467,14 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) break; } - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!mvm->trans->cfg->ext_nvm) { section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); } else { - section_size = 2 * NVM_WORD2_LEN_FAMILY_8000( + section_size = 2 * EXT_NVM_WORD2_LEN( le16_to_cpu(file_sec->word2)); - section_id = NVM_WORD1_ID_FAMILY_8000( + section_id = EXT_NVM_WORD1_ID( le16_to_cpu(file_sec->word1)); } @@ -551,12 +546,105 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) return ret; } +int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm) +{ + struct iwl_nvm_get_info cmd = {}; + struct iwl_nvm_get_info_rsp *rsp; + struct iwl_trans *trans = mvm->trans; + struct iwl_host_cmd hcmd = { + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, + .data = { &cmd, }, + .len = { sizeof(cmd) }, + .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) + }; + int ret; + bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + + lockdep_assert_held(&mvm->mutex); + + ret = iwl_mvm_send_cmd(mvm, &hcmd); + if (ret) + return ret; + + if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp), + "Invalid payload len in NVM response from FW %d", + iwl_rx_packet_payload_len(hcmd.resp_pkt))) { + ret = -EINVAL; + goto out; + } + + rsp = (void *)hcmd.resp_pkt->data; + if (le32_to_cpu(rsp->general.flags)) { + IWL_ERR(mvm, "Invalid NVM data from FW\n"); + ret = -EINVAL; + goto out; + } + + mvm->nvm_data = kzalloc(sizeof(*mvm->nvm_data) + + sizeof(struct ieee80211_channel) * + IWL_NUM_CHANNELS, GFP_KERNEL); + if (!mvm->nvm_data) { + ret = -ENOMEM; + goto out; + } + + iwl_set_hw_address_from_csr(trans, mvm->nvm_data); + /* TODO: if platform NVM has MAC address - override it here */ + + if (!is_valid_ether_addr(mvm->nvm_data->hw_addr)) { + IWL_ERR(trans, "no valid mac address was found\n"); + ret = -EINVAL; + goto err_free; + } + + IWL_INFO(trans, "base HW address: %pM\n", mvm->nvm_data->hw_addr); + + /* Initialize general data */ + mvm->nvm_data->nvm_version = le16_to_cpu(rsp->general.nvm_version); + + /* Initialize MAC sku data */ + mvm->nvm_data->sku_cap_11ac_enable = + le32_to_cpu(rsp->mac_sku.enable_11ac); + mvm->nvm_data->sku_cap_11n_enable = + le32_to_cpu(rsp->mac_sku.enable_11n); + mvm->nvm_data->sku_cap_band_24GHz_enable = + le32_to_cpu(rsp->mac_sku.enable_24g); + mvm->nvm_data->sku_cap_band_52GHz_enable = + le32_to_cpu(rsp->mac_sku.enable_5g); + mvm->nvm_data->sku_cap_mimo_disabled = + le32_to_cpu(rsp->mac_sku.mimo_disable); + + /* Initialize PHY sku data */ + mvm->nvm_data->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); + mvm->nvm_data->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); + + /* Initialize regulatory data */ + mvm->nvm_data->lar_enabled = + le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported; + + iwl_init_sbands(trans->dev, trans->cfg, mvm->nvm_data, + rsp->regulatory.channel_profile, + mvm->nvm_data->valid_tx_ant & mvm->fw->valid_tx_ant, + mvm->nvm_data->valid_rx_ant & mvm->fw->valid_rx_ant, + rsp->regulatory.lar_enabled && lar_fw_supported); + + iwl_free_resp(&hcmd); + return 0; + +err_free: + kfree(mvm->nvm_data); +out: + iwl_free_resp(&hcmd); + return ret; +} + int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) { int ret, section; u32 size_read = 0; u8 *nvm_buffer, *temp; - const char *nvm_file_B = mvm->cfg->default_nvm_file_B_step; const char *nvm_file_C = mvm->cfg->default_nvm_file_C_step; if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) @@ -626,14 +714,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) /* read External NVM file from the mod param */ ret = iwl_mvm_read_external_nvm(mvm); if (ret) { - /* choose the nvm_file name according to the - * HW step - */ - if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == - SILICON_B_STEP) - mvm->nvm_file_name = nvm_file_B; - else - mvm->nvm_file_name = nvm_file_C; + mvm->nvm_file_name = nvm_file_C; if ((ret == -EFAULT || ret == -ENOENT) && mvm->nvm_file_name) { @@ -704,6 +785,10 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * sizeof(__le32); resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); + if (!resp_cp) { + resp_cp = ERR_PTR(-ENOMEM); + goto exit; + } } else { struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data; @@ -711,21 +796,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * sizeof(__le32); resp_cp = kzalloc(resp_len, GFP_KERNEL); - - if (resp_cp) { - resp_cp->status = mcc_resp_v1->status; - resp_cp->mcc = mcc_resp_v1->mcc; - resp_cp->cap = mcc_resp_v1->cap; - resp_cp->source_id = mcc_resp_v1->source_id; - resp_cp->n_channels = mcc_resp_v1->n_channels; - memcpy(resp_cp->channels, mcc_resp_v1->channels, - n_channels * sizeof(__le32)); + if (!resp_cp) { + resp_cp = ERR_PTR(-ENOMEM); + goto exit; } - } - if (!resp_cp) { - ret = -ENOMEM; - goto exit; + resp_cp->status = mcc_resp_v1->status; + resp_cp->mcc = mcc_resp_v1->mcc; + resp_cp->cap = mcc_resp_v1->cap; + resp_cp->source_id = mcc_resp_v1->source_id; + resp_cp->n_channels = mcc_resp_v1->n_channels; + memcpy(resp_cp->channels, mcc_resp_v1->channels, + n_channels * sizeof(__le32)); } status = le32_to_cpu(resp_cp->status); @@ -745,8 +827,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, exit: iwl_free_resp(&cmd); - if (ret) - return ERR_PTR(ret); return resp_cp; } @@ -758,7 +838,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) struct ieee80211_regdomain *regd; char mcc[3]; - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + if (mvm->cfg->ext_nvm) { tlv_lar = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT); nvm_lar = mvm->nvm_data->lar_enabled; @@ -825,8 +905,8 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) return; - mcc[0] = notif->mcc >> 8; - mcc[1] = notif->mcc & 0xff; + mcc[0] = le16_to_cpu(notif->mcc) >> 8; + mcc[1] = le16_to_cpu(notif->mcc) & 0xff; mcc[2] = '\0'; src = notif->source_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3da5ec40aaea..4d1188b8736a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 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 @@ -33,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,10 +68,10 @@ #include <linux/vmalloc.h> #include <net/mac80211.h> -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-trans.h" #include "iwl-op-mode.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-debug.h" #include "iwl-drv.h" #include "iwl-modparams.h" @@ -172,13 +173,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); /* - * TODO: Bits 7-8 of CSR in 8000 HW family set the ADC sampling, and - * shouldn't be set to any non-zero value. The same is supposed to be - * true of the other HW, but unsetting them (such as the 7260) causes - * automatic tests to fail on seemingly unrelated errors. Need to - * further investigate this, but for now we'll separate cases. + * TODO: Bits 7-8 of CSR in 8000 HW family and higher set the ADC + * sampling, and shouldn't be set to any non-zero value. + * The same is supposed to be true of the other HW, but unsetting + * them (such as the 7260) causes automatic tests to fail on seemingly + * unrelated errors. Need to further investigate this, but for now + * we'll separate cases. */ - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, @@ -355,9 +357,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(SCAN_OFFLOAD_ABORT_CMD), HCMD_NAME(HOT_SPOT_CMD), HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD), - HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD), - HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD), - HCMD_NAME(BT_COEX_UPDATE_SW_BOOST), HCMD_NAME(BT_COEX_UPDATE_CORUN_LUT), HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP), HCMD_NAME(BT_COEX_CI), @@ -366,13 +365,11 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(PHY_DB_CMD), HCMD_NAME(SCAN_OFFLOAD_COMPLETE), HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), - HCMD_NAME(SCAN_OFFLOAD_CONFIG_CMD), HCMD_NAME(POWER_TABLE_CMD), HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), HCMD_NAME(REPLY_THERMAL_MNG_BACKOFF), HCMD_NAME(DC2DC_CONFIG_CMD), HCMD_NAME(NVM_ACCESS_CMD), - HCMD_NAME(SET_CALIB_DEFAULT_CMD), HCMD_NAME(BEACON_NOTIFICATION), HCMD_NAME(BEACON_TEMPLATE_CMD), HCMD_NAME(TX_ANT_CONFIGURATION_CMD), @@ -381,7 +378,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(STATISTICS_NOTIFICATION), HCMD_NAME(EOSP_NOTIFICATION), HCMD_NAME(REDUCE_TX_POWER_CMD), - HCMD_NAME(CARD_STATE_CMD), HCMD_NAME(CARD_STATE_NOTIFICATION), HCMD_NAME(MISSED_BEACONS_NOTIFICATION), HCMD_NAME(TDLS_CONFIG_CMD), @@ -396,8 +392,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(MCC_UPDATE_CMD), HCMD_NAME(MCC_CHUB_UPDATE_CMD), HCMD_NAME(MARKER_CMD), - HCMD_NAME(BT_COEX_PRIO_TABLE), - HCMD_NAME(BT_COEX_PROT_ENV), HCMD_NAME(BT_PROFILE_NOTIFICATION), HCMD_NAME(BCAST_FILTER_CMD), HCMD_NAME(MCAST_FILTER_CMD), @@ -408,7 +402,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(OFFLOADS_QUERY_CMD), HCMD_NAME(REMOTE_WAKE_CONFIG_CMD), HCMD_NAME(MATCH_FOUND_NOTIFICATION), - HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER), HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), HCMD_NAME(WOWLAN_PATTERNS), HCMD_NAME(WOWLAN_CONFIGURATION), @@ -416,11 +409,9 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(WOWLAN_TKIP_PARAM), HCMD_NAME(WOWLAN_KEK_KCK_MATERIAL), HCMD_NAME(WOWLAN_GET_STATUSES), - HCMD_NAME(WOWLAN_TX_POWER_PER_DB), HCMD_NAME(SCAN_ITERATION_COMPLETE), HCMD_NAME(D0I3_END_CMD), HCMD_NAME(LTR_CONFIG), - HCMD_NAME(REPLY_DEBUG_CMD), }; /* Please keep this array *SORTED* by hex value. @@ -483,6 +474,7 @@ static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = { HCMD_NAME(NVM_ACCESS_COMPLETE), + HCMD_NAME(NVM_GET_INFO), }; static const struct iwl_hcmd_arr iwl_mvm_groups[] = { @@ -588,6 +580,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw = fw; mvm->hw = hw; + mvm->init_status = 0; + if (iwl_mvm_has_new_rx_api(mvm)) { op_mode->ops = &iwl_mvm_ops_mq; trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc); @@ -600,7 +594,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, goto out_free; } - mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; + mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; if (!iwl_mvm_is_dqa_supported(mvm)) { mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1; @@ -608,9 +602,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (mvm->cfg->base_params->num_of_queues == 16) { mvm->aux_queue = 11; mvm->first_agg_queue = 12; + BUILD_BUG_ON(BITS_PER_BYTE * + sizeof(mvm->hw_queue_to_mac80211[0]) < 12); } else { mvm->aux_queue = 15; mvm->first_agg_queue = 16; + BUILD_BUG_ON(BITS_PER_BYTE * + sizeof(mvm->hw_queue_to_mac80211[0]) < 16); } } else { mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; @@ -747,12 +745,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mutex_lock(&mvm->mutex); iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE); err = iwl_run_init_mvm_ucode(mvm, true); - if (!err || !iwlmvm_mod_params.init_dbg) + if (!iwlmvm_mod_params.init_dbg) iwl_mvm_stop_device(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); mutex_unlock(&mvm->mutex); /* returns 0 if successful, 1 if success but in rfkill */ - if (err < 0 && !iwlmvm_mod_params.init_dbg) { + if (err < 0) { IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); goto out_free; } @@ -778,7 +776,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (err) goto out_unregister; - memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) + memset(&mvm->rx_stats_v3, 0, + sizeof(struct mvm_statistics_rx_v3)); + else + memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); /* The transport always starts with a taken reference, we can * release it now if d0i3 is supported */ @@ -790,12 +792,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, return op_mode; out_unregister: + if (iwlmvm_mod_params.init_dbg) + return op_mode; + ieee80211_unregister_hw(mvm->hw); mvm->hw_registered = false; iwl_mvm_leds_exit(mvm); iwl_mvm_thermal_exit(mvm); out_free: flush_delayed_work(&mvm->fw_dump_wk); + + if (iwlmvm_mod_params.init_dbg) + return op_mode; iwl_phy_db_free(mvm->phy_db); kfree(mvm->scan_cmd); iwl_trans_op_mode_leave(trans); @@ -820,7 +828,10 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_mvm_thermal_exit(mvm); - ieee80211_unregister_hw(mvm->hw); + if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) { + ieee80211_unregister_hw(mvm->hw); + mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE; + } kfree(mvm->scan_cmd); kfree(mvm->mcast_filter_cmd); @@ -835,7 +846,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_phy_db_free(mvm->phy_db); mvm->phy_db = NULL; - iwl_free_nvm_data(mvm->nvm_data); + kfree(mvm->nvm_data); for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); @@ -1080,6 +1091,16 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) iwl_mvm_start_mac_queues(mvm, mq); } +static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm) +{ + bool state = iwl_mvm_is_radio_killed(mvm); + + if (state) + wake_up(&mvm->rx_sync_waitq); + + wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); +} + void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) { if (state) @@ -1087,7 +1108,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) else clear_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); - wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); + iwl_mvm_set_rfkill_state(mvm); } static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) @@ -1100,7 +1121,7 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) else clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); - wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); + iwl_mvm_set_rfkill_state(mvm); /* iwl_run_init_mvm_ucode is waiting for results, abort it */ if (calibrating) @@ -1157,9 +1178,13 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) /* start recording again if the firmware is not crashed */ if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && - mvm->fw->dbg_dest_tlv) + mvm->fw->dbg_dest_tlv) { iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + iwl_clear_bits_prph(mvm->trans, + MON_BUFF_SAMPLE_CTL, 0x1); + iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x1); + } } else { u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE); u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL); @@ -1208,7 +1233,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * If WoWLAN fw asserted, don't restart either, mac80211 * can't recover this since we're already half suspended. */ - if (!mvm->restart_fw && fw_error) { + if (!mvm->fw_restart && fw_error) { iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, NULL); } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, @@ -1241,8 +1266,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); - if (fw_error && mvm->restart_fw > 0) - mvm->restart_fw--; + if (fw_error && mvm->fw_restart > 0) + mvm->fw_restart--; ieee80211_restart_hw(mvm->hw); } } @@ -1299,7 +1324,7 @@ static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm, * for offloading in order to prevent reuse of the same * qos seq counters. */ - if (iwl_mvm_tid_queued(tid_data)) + if (iwl_mvm_tid_queued(mvm, tid_data)) continue; if (tid_data->state != IWL_AGG_OFF) @@ -1449,9 +1474,15 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) synchronize_net(); /* Flush the hw queues, in case something got queued during entry */ - ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm), flags); - if (ret) - return ret; + /* TODO new tx api */ + if (iwl_mvm_has_new_tx_api(mvm)) { + WARN_ONCE(1, "d0i3: Need to implement flush TX queue\n"); + } else { + ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm), + flags); + if (ret) + return ret; + } /* configure wowlan configuration only if needed */ if (mvm->d0i3_ap_sta_id != IWL_MVM_INVALID_STA) { @@ -1597,9 +1628,6 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) if (ret) goto out; - if (!get_status_cmd.resp_pkt) - goto out; - status = (void *)get_status_cmd.resp_pkt->data; wakeup_reasons = le32_to_cpu(status->wakeup_reasons); qos_seq = status->qos_seq_ctr; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index d59efe804356..fb9eaf003ea5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -255,8 +255,8 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, lockdep_assert_held(&mvm->mutex); - /* In CDB mode we cannot modify PHY context between bands so... */ - if (iwl_mvm_has_new_tx_api(mvm) && + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && ctxt->channel->band != chandef->chan->band) { int ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index aa785cf3cf68..65beca3a457a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2836,7 +2836,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rs_get_initial_rate(mvm, sta, lq_sta, band, rate); rs_init_optimal_rate(mvm, sta, lq_sta); - WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); + WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B, + "ant: 0x%x, chains 0x%x, fw tx ant: 0x%x, nvm tx ant: 0x%x\n", + rate->ant, lq_sta->pers.chains, mvm->fw->valid_tx_ant, + mvm->nvm_data ? mvm->nvm_data->valid_tx_ant : ANT_INVALID); + tbl->column = rs_get_column_from_rate(rate); rs_set_expected_tpt_table(lq_sta, tbl); @@ -3229,7 +3233,11 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, if (num_of_ant(ant) == 1) lq_cmd->single_stream_ant_msk = ant; - lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + if (!mvm->trans->cfg->gen2) + lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + else + lq_cmd->agg_frame_cnt_limit = + LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF; } #endif /* CONFIG_MAC80211_DEBUGFS */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 3abde1cb0303..32b4d66debea 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -145,6 +145,8 @@ enum { #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) +#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF (64) +#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_MAX (64) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index fd1dd06c4f18..622d543abb70 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -133,7 +133,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, */ hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8; - memcpy(skb_put(skb, hdrlen), hdr, hdrlen); + skb_put_data(skb, hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { @@ -504,14 +504,6 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_unref(mvm, IWL_MVM_REF_RX); } -static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, - struct mvm_statistics_rx *rx_stats) -{ - lockdep_assert_held(&mvm->mutex); - - mvm->rx_stats = *rx_stats; -} - struct iwl_mvm_stat_data { struct iwl_mvm *mvm; __le32 mac_id; @@ -555,7 +547,6 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, mvmvif->beacon_stats.avg_signal = -general->beacon_average_energy[vif_id]; } - } if (mvmvif->id != id) @@ -651,7 +642,6 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { - struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; struct iwl_mvm_stat_data data = { .mvm = mvm, }; @@ -659,13 +649,16 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, int i; u8 *energy; __le32 *bytes, *air_time; + __le32 flags; - if (iwl_mvm_is_cdb_supported(mvm)) - expected_size = sizeof(*stats); - else if (iwl_mvm_has_new_rx_api(mvm)) - expected_size = sizeof(struct iwl_notif_statistics_v11); - else - expected_size = sizeof(struct iwl_notif_statistics_v10); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + if (iwl_mvm_has_new_rx_api(mvm)) + expected_size = sizeof(struct iwl_notif_statistics_v11); + else + expected_size = sizeof(struct iwl_notif_statistics_v10); + } else { + expected_size = sizeof(struct iwl_notif_statistics_cdb); + } if (iwl_rx_packet_payload_len(pkt) != expected_size) { IWL_ERR(mvm, "received invalid statistics size (%d)!\n", @@ -673,20 +666,49 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, return; } - data.mac_id = stats->rx.general.mac_id; - data.beacon_filter_average_energy = - stats->general.common.beacon_filter_average_energy; + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct iwl_notif_statistics_v11 *stats = (void *)&pkt->data; - iwl_mvm_update_rx_statistics(mvm, &stats->rx); + data.mac_id = stats->rx.general.mac_id; + data.beacon_filter_average_energy = + stats->general.common.beacon_filter_average_energy; - mvm->radio_stats.rx_time = le64_to_cpu(stats->general.common.rx_time); - mvm->radio_stats.tx_time = le64_to_cpu(stats->general.common.tx_time); - mvm->radio_stats.on_time_rf = - le64_to_cpu(stats->general.common.on_time_rf); - mvm->radio_stats.on_time_scan = - le64_to_cpu(stats->general.common.on_time_scan); + mvm->rx_stats_v3 = stats->rx; - data.general = &stats->general; + mvm->radio_stats.rx_time = + le64_to_cpu(stats->general.common.rx_time); + mvm->radio_stats.tx_time = + le64_to_cpu(stats->general.common.tx_time); + mvm->radio_stats.on_time_rf = + le64_to_cpu(stats->general.common.on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->general.common.on_time_scan); + + data.general = &stats->general; + + flags = stats->flag; + } else { + struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; + + data.mac_id = stats->rx.general.mac_id; + data.beacon_filter_average_energy = + stats->general.common.beacon_filter_average_energy; + + mvm->rx_stats = stats->rx; + + mvm->radio_stats.rx_time = + le64_to_cpu(stats->general.common.rx_time); + mvm->radio_stats.tx_time = + le64_to_cpu(stats->general.common.tx_time); + mvm->radio_stats.on_time_rf = + le64_to_cpu(stats->general.common.on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->general.common.on_time_scan); + + data.general = &stats->general; + + flags = stats->flag; + } iwl_mvm_rx_stats_check_trigger(mvm, pkt); @@ -698,14 +720,15 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, if (!iwl_mvm_has_new_rx_api(mvm)) return; - if (!iwl_mvm_is_cdb_supported(mvm)) { - struct iwl_notif_statistics_v11 *v11 = - (void *)&pkt->data; + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct iwl_notif_statistics_v11 *v11 = (void *)&pkt->data; energy = (void *)&v11->load_stats.avg_energy; bytes = (void *)&v11->load_stats.byte_count; air_time = (void *)&v11->load_stats.air_time; } else { + struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; + energy = (void *)&stats->load_stats.avg_energy; bytes = (void *)&stats->load_stats.byte_count; air_time = (void *)&stats->load_stats.air_time; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 966cd7543629..f3e608196369 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -183,9 +183,8 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, * present before copying packet data. */ hdrlen += crypt_len; - memcpy(skb_put(skb, hdrlen), hdr, hdrlen); - memcpy(skb_put(skb, headlen - hdrlen), (u8 *)hdr + hdrlen + pad_len, - headlen - hdrlen); + skb_put_data(skb, hdr, hdrlen); + skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); fraglen = len - headlen; @@ -503,7 +502,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data) buf->sta_id, sn); iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn); rcu_read_unlock(); - } else if (buf->num_stored) { + } else { /* * If no frame expired and there are stored frames, index is now * pointing to the first unexpired frame - modify timer diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 8d1b994ae79f..35e813bdfbe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1421,8 +1421,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->scan_vif = iwl_mvm_vif_from_mac80211(vif); iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); - queue_delayed_work(system_wq, &mvm->scan_timeout_dwork, - msecs_to_jiffies(SCAN_TIMEOUT)); + schedule_delayed_work(&mvm->scan_timeout_dwork, + msecs_to_jiffies(SCAN_TIMEOUT)); return 0; } @@ -1695,7 +1695,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) mvm->scan_uid_status[uid] = 0; } uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED); - if (uid >= 0 && !mvm->restart_fw) { + if (uid >= 0 && !mvm->fw_restart) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->scan_uid_status[uid] = 0; @@ -1725,7 +1725,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) * restarted. */ if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && - !mvm->restart_fw) { + !mvm->fw_restart) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 614d67810d05..4df5f13fcdae 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -398,7 +398,7 @@ static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue) struct iwl_mvm_sta *mvmsta; unsigned long tid_bitmap; unsigned long agg_tids = 0; - s8 sta_id; + u8 sta_id; int tid; lockdep_assert_held(&mvm->mutex); @@ -734,7 +734,6 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, spin_lock_bh(&mvmsta->lock); mvmsta->tid_data[tid].txq_id = queue; mvmsta->tid_data[tid].is_tid_active = true; - mvmsta->tfd_queue_msk |= BIT(queue); spin_unlock_bh(&mvmsta->lock); return 0; @@ -758,7 +757,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, bool using_inactive_queue = false, same_sta = false; unsigned long disable_agg_tids = 0; enum iwl_mvm_agg_state queue_state; - bool shared_queue = false; + bool shared_queue = false, inc_ssn; int ssn; unsigned long tfd_queue_mask; int ret; @@ -885,8 +884,12 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, } ssn = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - iwl_mvm_enable_txq(mvm, queue, mac_queue, ssn, &cfg, - wdg_timeout); + inc_ssn = iwl_mvm_enable_txq(mvm, queue, mac_queue, + ssn, &cfg, wdg_timeout); + if (inc_ssn) { + ssn = (ssn + 1) & IEEE80211_SCTL_SEQ; + le16_add_cpu(&hdr->seq_ctrl, 0x10); + } /* * Mark queue as shared in transport if shared @@ -898,6 +901,13 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); spin_lock_bh(&mvmsta->lock); + /* + * This looks racy, but it is not. We have only one packet for + * this ra/tid in our Tx path since we stop the Qdisc when we + * need to allocate a new TFD queue. + */ + if (inc_ssn) + mvmsta->tid_data[tid].seq_number += 0x10; mvmsta->tid_data[tid].txq_id = queue; mvmsta->tid_data[tid].is_tid_active = true; mvmsta->tfd_queue_msk |= BIT(queue); @@ -979,7 +989,7 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) { struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; - s8 sta_id; + u8 sta_id; int tid = -1; unsigned long tid_bitmap; unsigned int wdg_timeout; @@ -1344,7 +1354,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); mvm_sta->vif = vif; - mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + if (!mvm->trans->cfg->gen2) + mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + else + mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF; mvm_sta->tx_protection = 0; mvm_sta->tt_tx_protection = false; mvm_sta->sta_type = sta->tdls ? IWL_STA_TDLS_LINK : IWL_STA_LINK; @@ -1389,11 +1402,24 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (iwl_mvm_has_new_rx_api(mvm) && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + int q; + dup_data = kcalloc(mvm->trans->num_rx_queues, - sizeof(*dup_data), - GFP_KERNEL); + sizeof(*dup_data), GFP_KERNEL); if (!dup_data) return -ENOMEM; + /* + * Initialize all the last_seq values to 0xffff which can never + * compare equal to the frame's seq_ctrl in the check in + * iwl_mvm_is_dup() since the lower 4 bits are the fragment + * number and fragmented packets don't reach that function. + * + * This thus allows receiving a packet with seqno 0 and the + * retry bit set as the very first packet on a new TID. + */ + for (q = 0; q < mvm->trans->num_rx_queues; q++) + memset(dup_data[q].last_seq, 0xff, + sizeof(dup_data[q].last_seq)); mvm_sta->dup_data = dup_data; } @@ -1590,6 +1616,29 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, } } +int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvm_sta) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(mvm_sta->tid_data); i++) { + u16 txq_id; + + spin_lock_bh(&mvm_sta->lock); + txq_id = mvm_sta->tid_data[i].txq_id; + spin_unlock_bh(&mvm_sta->lock); + + if (txq_id == IWL_MVM_INVALID_QUEUE) + continue; + + ret = iwl_trans_wait_txq_empty(mvm->trans, txq_id); + if (ret) + break; + } + + return ret; +} + int iwl_mvm_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1611,11 +1660,17 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (ret) return ret; /* flush its queues here since we are freeing mvm_sta */ - ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, 0); + ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); if (ret) return ret; - ret = iwl_trans_wait_tx_queues_empty(mvm->trans, - mvm_sta->tfd_queue_msk); + if (iwl_mvm_has_new_tx_api(mvm)) { + ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta); + } else { + u32 q_mask = mvm_sta->tfd_queue_msk; + + ret = iwl_trans_wait_tx_queues_empty(mvm->trans, + q_mask); + } if (ret) return ret; ret = iwl_mvm_drain_sta(mvm, mvm_sta, false); @@ -1964,8 +2019,6 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvm->probe_queue = queue; else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mvm->p2p_dev_queue = queue; - - bsta->tfd_queue_msk |= BIT(queue); } return 0; @@ -1975,27 +2028,32 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int queue; lockdep_assert_held(&mvm->mutex); - if (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC) - iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, - IWL_MAX_TID_COUNT, 0); + iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true, 0); - if (mvmvif->bcast_sta.tfd_queue_msk & BIT(mvm->probe_queue)) { - iwl_mvm_disable_txq(mvm, mvm->probe_queue, - vif->hw_queue[0], IWL_MAX_TID_COUNT, - 0); - mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(mvm->probe_queue); + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + queue = mvm->probe_queue; + break; + case NL80211_IFTYPE_P2P_DEVICE: + queue = mvm->p2p_dev_queue; + break; + default: + WARN(1, "Can't free bcast queue on vif type %d\n", + vif->type); + return; } - if (mvmvif->bcast_sta.tfd_queue_msk & BIT(mvm->p2p_dev_queue)) { - iwl_mvm_disable_txq(mvm, mvm->p2p_dev_queue, - vif->hw_queue[0], IWL_MAX_TID_COUNT, - 0); - mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(mvm->p2p_dev_queue); - } + iwl_mvm_disable_txq(mvm, queue, vif->hw_queue[0], IWL_MAX_TID_COUNT, 0); + if (iwl_mvm_has_new_tx_api(mvm)) + return; + + WARN_ON(!(mvmvif->bcast_sta.tfd_queue_msk & BIT(queue))); + mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(queue); } /* Send the FW a request to remove the station from it's internal data @@ -2187,6 +2245,8 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (!iwl_mvm_is_dqa_supported(mvm)) return 0; + iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0); + iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, IWL_MAX_TID_COUNT, 0); @@ -2496,6 +2556,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; + u16 normalized_ssn; int txq_id; int ret; @@ -2583,7 +2644,15 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmsta->sta_id, tid, txq_id, tid_data->ssn, tid_data->next_reclaimed); - if (tid_data->ssn == tid_data->next_reclaimed) { + /* + * In A000 HW, the next_reclaimed index is only 8 bit, so we'll need + * to align the wrap around of ssn so we compare relevant values. + */ + normalized_ssn = tid_data->ssn; + if (mvm->trans->cfg->gen2) + normalized_ssn &= 0xff; + + if (normalized_ssn == tid_data->next_reclaimed) { tid_data->state = IWL_AGG_STARTING; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); } else { @@ -2624,7 +2693,11 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE) != IWL_MAX_TID_COUNT); - buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + if (!mvm->trans->cfg->gen2) + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + else + buf_size = min_t(int, buf_size, + LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF); spin_lock_bh(&mvmsta->lock); ssn = tid_data->ssn; @@ -2781,8 +2854,13 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, "ssn = %d, next_recl = %d\n", tid_data->ssn, tid_data->next_reclaimed); - /* There are still packets for this RA / TID in the HW */ - if (tid_data->ssn != tid_data->next_reclaimed) { + /* + * There are still packets for this RA / TID in the HW. + * Not relevant for DQA mode, since there is no need to disable + * the queue. + */ + if (!iwl_mvm_is_dqa_supported(mvm) && + tid_data->ssn != tid_data->next_reclaimed) { tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA; err = 0; break; @@ -2855,10 +2933,18 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (old_state >= IWL_AGG_ON) { iwl_mvm_drain_sta(mvm, mvmsta, true); - if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0)) - IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); - iwl_trans_wait_tx_queues_empty(mvm->trans, - mvmsta->tfd_queue_msk); + + if (iwl_mvm_has_new_tx_api(mvm)) { + if (iwl_mvm_flush_sta_tids(mvm, mvmsta->sta_id, + BIT(tid), 0)) + IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + iwl_trans_wait_txq_empty(mvm->trans, txq_id); + } else { + if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0)) + IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(txq_id)); + } + iwl_mvm_drain_sta(mvm, mvmsta, false); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); @@ -2937,7 +3023,7 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, } static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvm_sta, + u32 sta_id, struct ieee80211_key_conf *key, bool mcast, u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags, u8 key_offset) @@ -2955,6 +3041,9 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, bool new_api = fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TKIP_MIC_KEYS); + if (sta_id == IWL_MVM_INVALID_STA) + return -EINVAL; + keyidx = (key->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK; key_flags = cpu_to_le16(keyidx); @@ -3013,7 +3102,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u.cmd.common.key_offset = key_offset; u.cmd.common.key_flags = key_flags; - u.cmd.common.sta_id = mvm_sta->sta_id; + u.cmd.common.sta_id = sta_id; if (new_api) { u.cmd.transmit_seq_cnt = cpu_to_le64(pn); @@ -3146,19 +3235,37 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, u8 key_offset, bool mcast) { - struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); int ret; const u8 *addr; struct ieee80211_key_seq seq; u16 p1k[5]; + u32 sta_id; + + if (sta) { + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + + sta_id = mvm_sta->sta_id; + } else if (vif->type == NL80211_IFTYPE_AP && + !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + sta_id = mvmvif->mcast_sta.sta_id; + } else { + IWL_ERR(mvm, "Failed to find station id\n"); + return -EINVAL; + } switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_TKIP: + if (vif->type == NL80211_IFTYPE_AP) { + ret = -EINVAL; + break; + } addr = iwl_mvm_get_mac_addr(mvm, vif, sta); /* get phase 1 key from mac80211 */ ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, seq.tkip.iv32, p1k, 0, key_offset); break; case WLAN_CIPHER_SUITE_CCMP: @@ -3166,11 +3273,11 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, 0, NULL, 0, key_offset); break; default: - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, 0, NULL, 0, key_offset); } @@ -3191,6 +3298,9 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, int ret, size; u32 status; + if (sta_id == IWL_MVM_INVALID_STA) + return -EINVAL; + key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK); key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); @@ -3234,42 +3344,48 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); struct iwl_mvm_sta *mvm_sta; - u8 sta_id; + u8 sta_id = IWL_MVM_INVALID_STA; int ret; static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0}; lockdep_assert_held(&mvm->mutex); - /* Get the station id from the mvm local station table */ - mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); - if (!mvm_sta) { - IWL_ERR(mvm, "Failed to find station\n"); - return -EINVAL; - } - sta_id = mvm_sta->sta_id; + if (vif->type != NL80211_IFTYPE_AP || + keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + /* Get the station id from the mvm local station table */ + mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); + if (!mvm_sta) { + IWL_ERR(mvm, "Failed to find station\n"); + return -EINVAL; + } + sta_id = mvm_sta->sta_id; - if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { - ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); - goto end; - } + if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { + ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, + false); + goto end; + } - /* - * It is possible that the 'sta' parameter is NULL, and thus - * there is a need to retrieve the sta from the local station table. - */ - if (!sta) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(sta)) { - IWL_ERR(mvm, "Invalid station id\n"); - return -EINVAL; + /* + * It is possible that the 'sta' parameter is NULL, and thus + * there is a need to retrieve the sta from the local station + * table. + */ + if (!sta) { + sta = rcu_dereference_protected( + mvm->fw_id_to_mac_id[sta_id], + lockdep_is_held(&mvm->mutex)); + if (IS_ERR_OR_NULL(sta)) { + IWL_ERR(mvm, "Invalid station id\n"); + return -EINVAL; + } } - } - if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) - return -EINVAL; + if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) + return -EINVAL; + } /* If the key_offset is not pre-assigned, we need to find a * new offset to use. In normal cases, the offset is not @@ -3299,8 +3415,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, * to the same key slot (offset). * If this fails, remove the original as well. */ - if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || - keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { + if ((keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || + keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) && + sta) { ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, !mcast); if (ret) { @@ -3334,6 +3451,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); if (mvm_sta) sta_id = mvm_sta->sta_id; + else if (!sta && vif->type == NL80211_IFTYPE_AP && mcast) + sta_id = iwl_mvm_vif_from_mac80211(vif)->mcast_sta.sta_id; + IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", keyconf->keyidx, sta_id); @@ -3356,7 +3476,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, } mvm->fw_key_deleted[keyconf->hw_key_idx] = 0; - if (!mvm_sta) { + if (sta && !mvm_sta) { IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); return 0; } @@ -3387,7 +3507,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); if (WARN_ON_ONCE(!mvm_sta)) goto unlock; - iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + iwl_mvm_send_sta_key(mvm, mvm_sta->sta_id, keyconf, mcast, iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx); unlock: @@ -3463,7 +3583,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, return; } - n_queued = iwl_mvm_tid_queued(tid_data); + n_queued = iwl_mvm_tid_queued(mvm, tid_data); if (n_queued > remaining) { more_data = true; remaining = 0; @@ -3645,3 +3765,17 @@ void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif) rcu_read_unlock(); } + +u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data) +{ + u16 sn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); + + /* + * In A000 HW, the next_reclaimed index is only 8 bit, so we'll need + * to align the wrap around of ssn so we compare relevant values. + */ + if (mvm->trans->cfg->gen2) + sn &= 0xff; + + return ieee80211_sn_sub(sn, tid_data->next_reclaimed); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index ad62b67dceb2..05fecbe87da4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -341,12 +341,6 @@ struct iwl_mvm_tid_data { bool is_tid_active; }; -static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) -{ - return ieee80211_sn_sub(IEEE80211_SEQ_TO_SN(tid_data->seq_number), - tid_data->next_reclaimed); -} - struct iwl_mvm_key_pn { struct rcu_head rcu_head; struct { @@ -447,6 +441,8 @@ struct iwl_mvm_sta { u8 avg_energy; }; +u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data); + static inline struct iwl_mvm_sta * iwl_mvm_sta_from_mac80211(struct ieee80211_sta *sta) { @@ -489,6 +485,8 @@ static inline int iwl_mvm_update_sta(struct iwl_mvm *mvm, return iwl_mvm_sta_send_to_fw(mvm, sta, true, 0); } +int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvm_sta); int iwl_mvm_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index df7cd87199ea..3d97436bbdf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -551,8 +551,7 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work) /* retry after a DTIM if we failed sending now */ delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); - queue_delayed_work(system_wq, &mvm->tdls_cs.dwork, - msecs_to_jiffies(delay)); + schedule_delayed_work(&mvm->tdls_cs.dwork, msecs_to_jiffies(delay)); out: mutex_unlock(&mvm->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 2c12789e7550..5a682722adce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -66,7 +66,7 @@ #include <linux/jiffies.h> #include <net/mac80211.h> -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-trans.h" #include "fw-api.h" #include "time-event.h" @@ -130,7 +130,10 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) * issue as it will have to complete before the next command is * executed, and a new time event means a new command. */ - iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC); + if (iwl_mvm_is_dqa_supported(mvm)) + iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC); + else + iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC); } static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c index 16ce8a56b5b9..634175b2480c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c @@ -93,17 +93,21 @@ void iwl_mvm_tof_init(struct iwl_mvm *mvm) cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + mvm->init_status |= IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE; } void iwl_mvm_tof_clean(struct iwl_mvm *mvm) { struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_TOF_SUPPORT) || + !(mvm->init_status & IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE)) return; memset(tof_data, 0, sizeof(*tof_data)); mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + mvm->init_status &= ~IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE; } static void iwl_tof_iterator(void *_data, u8 *mac, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 506d58104e1c..453a785a3ea5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -628,7 +628,8 @@ static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device, mutex_lock(&mvm->mutex); - if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) { ret = -EIO; goto out; } @@ -678,7 +679,8 @@ static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device, mutex_lock(&mvm->mutex); - if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) { ret = -EIO; goto out; } @@ -792,7 +794,8 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev, mutex_lock(&mvm->mutex); - if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) { ret = -EIO; goto unlock; } @@ -884,10 +887,14 @@ void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff) iwl_mvm_cooling_device_register(mvm); iwl_mvm_thermal_zone_register(mvm); #endif + mvm->init_status |= IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE; } void iwl_mvm_thermal_exit(struct iwl_mvm *mvm) { + if (!(mvm->init_status & IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE)) + return; + cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); @@ -895,4 +902,5 @@ void iwl_mvm_thermal_exit(struct iwl_mvm *mvm) iwl_mvm_cooling_device_unregister(mvm); iwl_mvm_thermal_zone_unregister(mvm); #endif + mvm->init_status &= ~IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index f21901cd4a4f..60360ed73f26 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -105,9 +105,9 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, static u16 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_hdr *hdr, - struct ieee80211_tx_info *info) + struct ieee80211_tx_info *info, + u16 offload_assist) { - u16 offload_assist = 0; #if IS_ENABLED(CONFIG_INET) u16 mh_len = ieee80211_hdrlen(hdr->frame_control); u8 protocol = 0; @@ -207,6 +207,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, __le16 fc = hdr->frame_control; u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); u32 len = skb->len + FCS_LEN; + u16 offload_assist = 0; u8 ac; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -225,8 +226,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL; if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) - tx_cmd->offload_assist |= - cpu_to_le16(BIT(TX_CMD_OFFLD_AMSDU)); + offload_assist |= BIT(TX_CMD_OFFLD_AMSDU); } else if (ieee80211_is_back_req(fc)) { struct ieee80211_bar *bar = (void *)skb->data; u16 control = le16_to_cpu(bar->control); @@ -291,11 +291,12 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, /* padding is inserted later in transport */ if (ieee80211_hdrlen(fc) % 4 && - !(tx_cmd->offload_assist & cpu_to_le16(BIT(TX_CMD_OFFLD_AMSDU)))) - tx_cmd->offload_assist |= cpu_to_le16(BIT(TX_CMD_OFFLD_PAD)); + !(offload_assist & BIT(TX_CMD_OFFLD_AMSDU))) + offload_assist |= BIT(TX_CMD_OFFLD_PAD); tx_cmd->offload_assist |= - cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, hdr, info)); + cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, hdr, info, + offload_assist)); } static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, @@ -473,15 +474,27 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, if (unlikely(!dev_cmd)) return NULL; - memset(dev_cmd, 0, sizeof(*dev_cmd)); + /* Make sure we zero enough of dev_cmd */ + BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_gen2) > sizeof(*tx_cmd)); + + memset(dev_cmd, 0, sizeof(dev_cmd->hdr) + sizeof(*tx_cmd)); dev_cmd->hdr.cmd = TX_CMD; if (iwl_mvm_has_new_tx_api(mvm)) { struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; - u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info); + u16 offload_assist = 0; + + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + + if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) + offload_assist |= BIT(TX_CMD_OFFLD_AMSDU); + } + + offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info, + offload_assist); /* padding is inserted later in transport */ - /* FIXME - check for AMSDU may need to be removed */ if (ieee80211_hdrlen(hdr->frame_control) % 4 && !(offload_assist & BIT(TX_CMD_OFFLD_AMSDU))) offload_assist |= BIT(TX_CMD_OFFLD_PAD); @@ -538,22 +551,32 @@ static void iwl_mvm_skb_prepare_status(struct sk_buff *skb, static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, __le16 fc) { + struct iwl_mvm_vif *mvmvif; + if (!iwl_mvm_is_dqa_supported(mvm)) return info->hw_queue; + mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); + switch (info->control.vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: /* - * Handle legacy hostapd as well, where station may be added - * only after assoc. Take care of the case where we send a - * deauth to a station that we don't have. + * Handle legacy hostapd as well, where station will be added + * only just before sending the association response. + * Also take care of the case where we send a deauth to a + * station that we don't have, or similarly an association + * response (with non-success status) for a station we can't + * accept. + * Also, disassociate frames might happen, particular with + * reason 7 ("Class 3 frame received from nonassociated STA"). */ if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || - ieee80211_is_deauth(fc)) + ieee80211_is_deauth(fc) || ieee80211_is_assoc_resp(fc) || + ieee80211_is_disassoc(fc)) return mvm->probe_queue; if (info->hw_queue == info->control.vif->cab_queue) - return info->hw_queue; + return mvmvif->cab_queue; WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC, "fc=0x%02x", le16_to_cpu(fc)); @@ -562,7 +585,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, if (ieee80211_is_mgmt(fc)) return mvm->p2p_dev_queue; if (info->hw_queue == info->control.vif->cab_queue) - return info->hw_queue; + return mvmvif->cab_queue; WARN_ON_ONCE(1); return mvm->p2p_dev_queue; @@ -611,10 +634,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) * (this is not possible for unicast packets as a TLDS discovery * response are sent without a station entry); otherwise use the * AUX station. - * In DQA mode, if vif is of type STATION and frames are not multicast - * or offchannel, they should be sent from the BSS queue. - * For example, TDLS setup frames should be sent on this queue, - * as they go through the AP. */ sta_id = mvm->aux_sta.sta_id; if (info.control.vif) { @@ -629,9 +648,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) hdr->frame_control); if (queue < 0) return -1; - - if (queue == info.control.vif->cab_queue) - queue = mvmvif->cab_queue; } else if (info.control.vif->type == NL80211_IFTYPE_STATION && is_multicast_ether_addr(hdr->addr1)) { u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id); @@ -639,9 +655,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (ap_sta_id != IWL_MVM_INVALID_STA) sta_id = ap_sta_id; } else if (iwl_mvm_is_dqa_supported(mvm) && - info.control.vif->type == NL80211_IFTYPE_STATION && - queue != mvm->aux_queue) { - queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE; + info.control.vif->type == NL80211_IFTYPE_MONITOR) { + queue = mvm->aux_queue; } } @@ -695,11 +710,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + tcp_hdrlen(skb); - qc = ieee80211_get_qos_ctl(hdr); - tid = *qc & IEEE80211_QOS_CTL_TID_MASK; - if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) - return -EINVAL; - dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len); if (!sta->max_amsdu_len || @@ -710,6 +720,11 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, goto segment; } + qc = ieee80211_get_qos_ctl(hdr); + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) + return -EINVAL; + /* * Do not build AMSDU for IPv6 with extension headers. * ask stack to segment and checkum the generated MPDUs for us. @@ -829,11 +844,13 @@ segment: if (tcp_payload_len > mss) { skb_shinfo(tmp)->gso_size = mss; } else { - qc = ieee80211_get_qos_ctl((void *)tmp->data); + if (ieee80211_is_data_qos(hdr->frame_control)) { + qc = ieee80211_get_qos_ctl((void *)tmp->data); - if (ipv4) - ip_send_check(ip_hdr(tmp)); - *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + if (ipv4) + ip_send_check(ip_hdr(tmp)); + *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + } skb_shinfo(tmp)->gso_size = 0; } @@ -1120,13 +1137,14 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; struct ieee80211_vif *vif = mvmsta->vif; + u16 normalized_ssn; lockdep_assert_held(&mvmsta->lock); if ((tid_data->state == IWL_AGG_ON || tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA || iwl_mvm_is_dqa_supported(mvm)) && - iwl_mvm_tid_queued(tid_data) == 0) { + iwl_mvm_tid_queued(mvm, tid_data) == 0) { /* * Now that this aggregation or DQA queue is empty tell * mac80211 so it knows we no longer have frames buffered for @@ -1135,7 +1153,15 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, ieee80211_sta_set_buffered(sta, tid, false); } - if (tid_data->ssn != tid_data->next_reclaimed) + /* + * In A000 HW, the next_reclaimed index is only 8 bit, so we'll need + * to align the wrap around of ssn so we compare relevant values. + */ + normalized_ssn = tid_data->ssn; + if (mvm->trans->cfg->gen2) + normalized_ssn &= 0xff; + + if (normalized_ssn != tid_data->next_reclaimed) return; switch (tid_data->state) { @@ -1313,6 +1339,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, struct ieee80211_sta *sta; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); + /* struct iwl_mvm_tx_resp_v3 is almost the same */ struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); @@ -1330,7 +1357,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, __skb_queue_head_init(&skbs); if (iwl_mvm_has_new_tx_api(mvm)) - txq_id = le16_to_cpu(tx_resp->v6.tx_queue); + txq_id = le16_to_cpu(tx_resp->tx_queue); seq_ctl = le16_to_cpu(tx_resp->seq_ctl); @@ -1479,7 +1506,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, if (mvmsta->sleep_tx_count) { mvmsta->sleep_tx_count--; if (mvmsta->sleep_tx_count && - !iwl_mvm_tid_queued(tid_data)) { + !iwl_mvm_tid_queued(mvm, tid_data)) { /* * The number of frames in the queue * dropped to 0 even if we sent less @@ -1791,6 +1818,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) if (iwl_mvm_has_new_tx_api(mvm)) { struct iwl_mvm_compressed_ba_notif *ba_res = (void *)pkt->data; + int i; sta_id = ba_res->sta_id; ba_info.status.ampdu_ack_len = (u8)le16_to_cpu(ba_res->done); @@ -1803,22 +1831,17 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) if (!le16_to_cpu(ba_res->tfd_cnt)) goto out; - /* - * TODO: - * When supporting multi TID aggregations - we need to move - * next_reclaimed to be per TXQ and not per TID or handle it - * in a different way. - * This will go together with SN and AddBA offload and cannot - * be handled properly for now. - */ - WARN_ON(le16_to_cpu(ba_res->ra_tid_cnt) != 1); - tid = ba_res->ra_tid[0].tid; - if (tid == IWL_MGMT_TID) - tid = IWL_MAX_TID_COUNT; - iwl_mvm_tx_reclaim(mvm, sta_id, tid, - (int)(le16_to_cpu(ba_res->tfd[0].q_num)), - le16_to_cpu(ba_res->tfd[0].tfd_index), - &ba_info, le32_to_cpu(ba_res->tx_rate)); + /* Free per TID */ + for (i = 0; i < le16_to_cpu(ba_res->tfd_cnt); i++) { + struct iwl_mvm_compressed_ba_tfd *ba_tfd = + &ba_res->tfd[i]; + + iwl_mvm_tx_reclaim(mvm, sta_id, ba_tfd->tid, + (int)(le16_to_cpu(ba_tfd->q_num)), + le16_to_cpu(ba_tfd->tfd_index), + &ba_info, + le32_to_cpu(ba_res->tx_rate)); + } out: IWL_DEBUG_TX_REPLY(mvm, @@ -1860,7 +1883,7 @@ out: IWL_DEBUG_TX_REPLY(mvm, "BA_NOTIFICATION Received from %pM, sta_id = %d\n", - (u8 *)&ba_notif->sta_addr_lo32, ba_notif->sta_id); + ba_notif->sta_addr, ba_notif->sta_id); IWL_DEBUG_TX_REPLY(mvm, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n", @@ -1883,14 +1906,55 @@ out: int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags) { int ret; - struct iwl_tx_path_flush_cmd flush_cmd = { + struct iwl_tx_path_flush_cmd_v1 flush_cmd = { .queues_ctl = cpu_to_le32(tfd_msk), .flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH), }; + WARN_ON(iwl_mvm_has_new_tx_api(mvm)); + + ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags, + sizeof(flush_cmd), &flush_cmd); + if (ret) + IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret); + return ret; +} + +int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id, + u16 tids, u32 flags) +{ + int ret; + struct iwl_tx_path_flush_cmd flush_cmd = { + .sta_id = cpu_to_le32(sta_id), + .tid_mask = cpu_to_le16(tids), + }; + + WARN_ON(!iwl_mvm_has_new_tx_api(mvm)); + ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags, sizeof(flush_cmd), &flush_cmd); if (ret) IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret); return ret; } + +int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) +{ + struct iwl_mvm_int_sta *int_sta = sta; + struct iwl_mvm_sta *mvm_sta = sta; + + if (iwl_mvm_has_new_tx_api(mvm)) { + if (internal) + return iwl_mvm_flush_sta_tids(mvm, int_sta->sta_id, + BIT(IWL_MGMT_TID), flags); + + return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id, + 0xFF, flags); + } + + if (internal) + return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk, + flags); + + return iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, flags); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 8f4f176e204e..fc5a490880d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -69,6 +69,7 @@ #include "iwl-debug.h" #include "iwl-io.h" #include "iwl-prph.h" +#include "iwl-csr.h" #include "fw-dbg.h" #include "mvm.h" #include "fw-api-rs.h" @@ -168,11 +169,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, } pkt = cmd->resp_pkt; - /* Can happen if RFKILL is asserted */ - if (!pkt) { - ret = 0; - goto out_free_resp; - } resp_len = iwl_rx_packet_payload_len(pkt); if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { @@ -502,6 +498,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) { struct iwl_trans *trans = mvm->trans; struct iwl_error_event_table table; + u32 val; if (mvm->cur_ucode == IWL_UCODE_INIT) { if (!base) @@ -520,6 +517,36 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) return; } + /* check if there is a HW error */ + val = iwl_trans_read_mem32(trans, base); + if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { + int err; + + IWL_ERR(trans, "HW error, resetting before reading\n"); + + /* reset the device */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + usleep_range(5000, 6000); + + /* set INIT_DONE flag */ + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* and wait for clock stabilization */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + udelay(2); + + err = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); + if (err < 0) { + IWL_DEBUG_INFO(trans, + "Failed to reset the card for the dump\n"); + return; + } + } + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { @@ -671,7 +698,13 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, if (mvm->queue_info[queue].hw_queue_refcount > 0) enable_queue = false; - mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) { + WARN(mac80211_queue >= + BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]), + "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n", + mac80211_queue, queue, sta_id, tid); + mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + } mvm->queue_info[queue].hw_queue_refcount++; mvm->queue_info[queue].tid_bitmap |= BIT(tid); @@ -730,35 +763,39 @@ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, return queue; } -void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, +bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout) { + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .action = SCD_CFG_ENABLE_QUEUE, + .window = cfg->frame_limit, + .sta_id = cfg->sta_id, + .ssn = cpu_to_le16(ssn), + .tx_fifo = cfg->fifo, + .aggregate = cfg->aggregate, + .tid = cfg->tid, + }; + bool inc_ssn; + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) - return; + return false; /* Send the enabling command if we need to */ - if (iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, - cfg->sta_id, cfg->tid)) { - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .action = SCD_CFG_ENABLE_QUEUE, - .window = cfg->frame_limit, - .sta_id = cfg->sta_id, - .ssn = cpu_to_le16(ssn), - .tx_fifo = cfg->fifo, - .aggregate = cfg->aggregate, - .tid = cfg->tid, - }; - - iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, - wdg_timeout); - WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, - sizeof(struct iwl_scd_txq_cfg_cmd), - &cmd), - "Failed to configure queue %d on FIFO %d\n", queue, - cfg->fifo); - } + if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, + cfg->sta_id, cfg->tid)) + return false; + + inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, + NULL, wdg_timeout); + if (inc_ssn) + le16_add_cpu(&cmd.ssn, 1); + + WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), + "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); + + return inc_ssn; } int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, @@ -1186,7 +1223,11 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { /* If some TFDs are still queued - don't mark TID as inactive */ - if (iwl_mvm_tid_queued(&mvmsta->tid_data[tid])) + if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid])) + tid_bitmap &= ~BIT(tid); + + /* Don't mark as inactive any TID that has an active BA */ + if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) tid_bitmap &= ~BIT(tid); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index b1f43397bb59..eddaca76d514 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -103,6 +103,7 @@ static void iwl_pcie_ctxt_info_free_fw_img(struct iwl_trans *trans) kfree(dram->fw); dram->fw_cnt = 0; + dram->fw = NULL; } void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans) @@ -124,6 +125,7 @@ void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans) kfree(dram->paging); dram->paging_cnt = 0; + dram->paging = NULL; } static int iwl_pcie_ctxt_info_init_fw_sec(struct iwl_trans *trans, @@ -135,6 +137,11 @@ static int iwl_pcie_ctxt_info_init_fw_sec(struct iwl_trans *trans, struct iwl_context_info_dram *ctxt_dram = &ctxt_info->dram; int i, ret, lmac_cnt, umac_cnt, paging_cnt; + if (WARN(dram->paging, + "paging shouldn't already be initialized (%d pages)\n", + dram->paging_cnt)) + iwl_pcie_ctxt_info_free_paging(trans); + lmac_cnt = iwl_pcie_get_num_sections(fw, 0); /* add 1 due to separator */ umac_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + 1); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index e51760e752d4..f16c1bb9bf94 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -7,7 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016-2017 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 @@ -35,6 +35,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. + * Copyright(c) 2017 Intel Deutschland GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -535,10 +536,27 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1030, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)}, /* a000 Series */ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)}, - {IWL_PCI_DEVICE(0x2722, 0x0A10, iwla000_2ac_cfg_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0310, iwla000_2ac_cfg_jf)}, + {IWL_PCI_DEVICE(0x2720, 0x0000, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0070, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0078, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0070, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x1080, iwla000_2ax_cfg_hr)}, #endif /* CONFIG_IWLMVM */ {0} @@ -672,10 +690,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_trans->cfg = cfg_7265d; } - if (iwl_trans->cfg->rf_id && - (cfg == &iwla000_2ac_cfg_hr || cfg == &iwla000_2ac_cfg_hr_cdb) && - iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) { - cfg = &iwla000_2ac_cfg_jf; + if (iwl_trans->cfg->rf_id && cfg == &iwla000_2ac_cfg_hr_cdb) { + if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) + cfg = &iwla000_2ac_cfg_jf; + else if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_HR) + cfg = &iwla000_2ac_cfg_hr; + iwl_trans->cfg = cfg; } #endif @@ -703,7 +723,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, - iwlwifi_mod_params.d0i3_entry_delay); + iwlwifi_mod_params.d0i3_timeout); pm_runtime_use_autosuspend(&pdev->dev); /* We are not supposed to call pm_runtime_allow() by @@ -764,7 +784,6 @@ static int iwl_pci_resume(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct iwl_trans *trans = pci_get_drvdata(pdev); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - bool hw_rfkill; /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -780,17 +799,17 @@ static int iwl_pci_resume(struct device *device) if (!trans->op_mode) return 0; + /* reconfigure the MSI-X mapping to get the correct IRQ for rfkill */ + iwl_pcie_conf_msix_hw(trans_pcie); + /* - * Enable rfkill interrupt (in order to keep track of - * the rfkill status). Must be locked to avoid processing - * a possible rfkill interrupt between reading the state - * and calling iwl_trans_pcie_rf_kill() with it. + * Enable rfkill interrupt (in order to keep track of the rfkill + * status). Must be locked to avoid processing a possible rfkill + * interrupt while in iwl_trans_check_hw_rf_kill(). */ mutex_lock(&trans_pcie->mutex); iwl_enable_rfkill_int(trans); - - hw_rfkill = iwl_is_rfkill_set(trans); - iwl_trans_pcie_rf_kill(trans, hw_rfkill); + iwl_trans_check_hw_rf_kill(trans); mutex_unlock(&trans_pcie->mutex); return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index fd4faaaa1484..fa315d84e98e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -403,7 +403,8 @@ struct iwl_trans_pcie { dma_addr_t ict_tbl_dma; int ict_index; bool use_ict; - bool is_down; + bool is_down, opmode_down; + bool debug_rfkill; struct isr_statistics isr_stats; spinlock_t irq_lock; @@ -515,7 +516,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans); void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); -void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, +bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout); void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, @@ -653,6 +654,13 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) } } +static inline void iwl_pcie_sw_reset(struct iwl_trans *trans) +{ + /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + usleep_range(5000, 6000); +} + static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, struct iwl_txq *txq, int idx) { @@ -673,8 +681,20 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) iwl_enable_hw_int_msk_msix(trans, MSIX_HW_INT_CAUSES_REG_RF_KILL); } + + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_9000) { + /* + * On 9000-series devices this bit isn't enabled by default, so + * when we power down the device we need set the bit to allow it + * to wake up the PCI-E bus for RF-kill interrupts. + */ + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); + } } +void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans); + static inline void iwl_wake_queue(struct iwl_trans *trans, struct iwl_txq *txq) { @@ -713,7 +733,12 @@ static inline u8 get_cmd_index(struct iwl_txq *q, u32 index) static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) { - lockdep_assert_held(&IWL_TRANS_GET_PCIE_TRANS(trans)->mutex); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->mutex); + + if (trans_pcie->debug_rfkill) + return true; return !(iwl_read32(trans, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); @@ -767,9 +792,11 @@ void iwl_pcie_apm_config(struct iwl_trans *trans); int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); +void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans, + bool was_in_rfkill); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); -int iwl_pcie_apm_stop_master(struct iwl_trans *trans); +void iwl_pcie_apm_stop_master(struct iwl_trans *trans); void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie); int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, bool cmd_queue); @@ -779,6 +806,9 @@ int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr, size_t size); void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); void iwl_pcie_apply_destination(struct iwl_trans *trans); +#ifdef CONFIG_INET +struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len); +#endif /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 1da2de205cdf..351c4423125a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -761,6 +761,15 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable) { + if (trans->cfg->device_family != IWL_DEVICE_FAMILY_9000) + return; + + if (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP) + return; + + if (!trans->cfg->integrated) + return; + /* * Turn on the chicken-bits that cause MAC wakeup for RX-related * values. @@ -768,12 +777,10 @@ void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable) * bug where shadow registers are not in the retention list and their * value is lost when NIC powers down */ - if (trans->cfg->integrated) { - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, - CSR_MAC_SHADOW_REG_CTRL_RX_WAKE); - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2, - CSR_MAC_SHADOW_REG_CTL2_RX_WAKE); - } + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, + CSR_MAC_SHADOW_REG_CTRL_RX_WAKE); + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2, + CSR_MAC_SHADOW_REG_CTL2_RX_WAKE); } static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) @@ -845,14 +852,14 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) * Set RX DMA chunk size to 64B for IOSF and 128B for PCIe * Default queue is 0 */ - iwl_write_prph_no_grab(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP | - (DEFAULT_RXQ_NUM << - RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) | + iwl_write_prph_no_grab(trans, RFH_GEN_CFG, + RFH_GEN_CFG_RFH_DMA_SNOOP | + RFH_GEN_CFG_VAL(DEFAULT_RXQ_NUM, 0) | RFH_GEN_CFG_SERVICE_DMA_SNOOP | - (trans->cfg->integrated ? - RFH_GEN_CFG_RB_CHUNK_SIZE_64 : - RFH_GEN_CFG_RB_CHUNK_SIZE_128) << - RFH_GEN_CFG_RB_CHUNK_SIZE_POS); + RFH_GEN_CFG_VAL(RB_CHUNK_SIZE, + trans->cfg->integrated ? + RFH_GEN_CFG_RB_CHUNK_SIZE_64 : + RFH_GEN_CFG_RB_CHUNK_SIZE_128)); /* Enable the relevant rx queues */ iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled); @@ -1119,15 +1126,23 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, pkt = rxb_addr(&rxcb); - if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) + if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) { + IWL_DEBUG_RX(trans, + "Q %d: RB end marker at offset %d\n", + rxq->id, offset); break; + } - WARN_ON((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> - FH_RSCSR_RXQ_POS != rxq->id); + WARN((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> + FH_RSCSR_RXQ_POS != rxq->id, + "frame on invalid queue - is on %d and indicates %d\n", + rxq->id, + (le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> + FH_RSCSR_RXQ_POS); IWL_DEBUG_RX(trans, - "cmd at offset %d: %s (%.2x.%2x, seq 0x%x)\n", - rxcb._offset, + "Q %d: cmd at offset %d: %s (%.2x.%2x, seq 0x%x)\n", + rxq->id, offset, iwl_get_cmd_string(trans, iwl_cmd_id(pkt->hdr.cmd, pkt->hdr.group_id, @@ -1376,6 +1391,8 @@ irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id) struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry); struct iwl_trans *trans = trans_pcie->trans; + trace_iwlwifi_dev_irq_msix(trans->dev, entry, false, 0, 0); + if (WARN_ON(entry->entry >= trans->num_rx_queues)) return IRQ_NONE; @@ -1413,18 +1430,16 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) return; } - local_bh_disable(); - /* The STATUS_FW_ERROR bit is set in this function. This must happen - * before we wake up the command caller, to ensure a proper cleanup. */ - iwl_trans_fw_error(trans); - local_bh_enable(); - for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { if (!trans_pcie->txq[i]) continue; del_timer(&trans_pcie->txq[i]->stuck_timer); } + /* The STATUS_FW_ERROR bit is set in this function. This must happen + * before we wake up the command caller, to ensure a proper cleanup. */ + iwl_trans_fw_error(trans); + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans_pcie->wait_command_queue); } @@ -1509,6 +1524,46 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans) return inta; } +void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct isr_statistics *isr_stats = &trans_pcie->isr_stats; + bool hw_rfkill, prev, report; + + mutex_lock(&trans_pcie->mutex); + prev = test_bit(STATUS_RFKILL_OPMODE, &trans->status); + hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) { + set_bit(STATUS_RFKILL_OPMODE, &trans->status); + set_bit(STATUS_RFKILL_HW, &trans->status); + } + if (trans_pcie->opmode_down) + report = hw_rfkill; + else + report = test_bit(STATUS_RFKILL_OPMODE, &trans->status); + + IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", + hw_rfkill ? "disable radio" : "enable radio"); + + isr_stats->rfkill++; + + if (prev != report) + iwl_trans_pcie_rf_kill(trans, report); + mutex_unlock(&trans_pcie->mutex); + + if (hw_rfkill) { + if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, + &trans->status)) + IWL_DEBUG_RF_KILL(trans, + "Rfkill while SYNC HCMD in flight\n"); + wake_up(&trans_pcie->wait_command_queue); + } else { + clear_bit(STATUS_RFKILL_HW, &trans->status); + if (trans_pcie->opmode_down) + clear_bit(STATUS_RFKILL_OPMODE, &trans->status); + } +} + irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) { struct iwl_trans *trans = dev_id; @@ -1632,30 +1687,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) /* HW RF KILL switch toggled */ if (inta & CSR_INT_BIT_RF_KILL) { - bool hw_rfkill; - - mutex_lock(&trans_pcie->mutex); - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - - IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", - hw_rfkill ? "disable radio" : "enable radio"); - - isr_stats->rfkill++; - - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - mutex_unlock(&trans_pcie->mutex); - if (hw_rfkill) { - if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, - &trans->status)) - IWL_DEBUG_RF_KILL(trans, - "Rfkill while SYNC HCMD in flight\n"); - wake_up(&trans_pcie->wait_command_queue); - } else { - clear_bit(STATUS_RFKILL, &trans->status); - } - + iwl_pcie_handle_rfkill_irq(trans); handled |= CSR_INT_BIT_RF_KILL; } @@ -1902,6 +1934,8 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) iwl_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); spin_unlock(&trans_pcie->irq_lock); + trace_iwlwifi_dev_irq_msix(trans->dev, entry, true, inta_fh, inta_hw); + if (unlikely(!(inta_fh | inta_hw))) { IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); lock_map_release(&trans->sync_cmd_lockdep_map); @@ -1982,31 +2016,8 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) } /* HW RF KILL switch toggled */ - if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL) { - bool hw_rfkill; - - mutex_lock(&trans_pcie->mutex); - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - - IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", - hw_rfkill ? "disable radio" : "enable radio"); - - isr_stats->rfkill++; - - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - mutex_unlock(&trans_pcie->mutex); - if (hw_rfkill) { - if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, - &trans->status)) - IWL_DEBUG_RF_KILL(trans, - "Rfkill while SYNC HCMD in flight\n"); - wake_up(&trans_pcie->wait_command_queue); - } else { - clear_bit(STATUS_RFKILL, &trans->status); - } - } + if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL) + iwl_pcie_handle_rfkill_irq(trans); if (inta_hw & MSIX_HW_INT_CAUSES_REG_HW_ERR) { IWL_ERR(trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index ac60a282d6de..b84b78293e7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -136,9 +136,7 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) /* Stop device's DMA activity */ iwl_pcie_apm_stop_master(trans); - /* Reset the entire device */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Clear "initialization complete" bit to move adapter from @@ -150,7 +148,6 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - bool hw_rfkill, was_hw_rfkill; lockdep_assert_held(&trans_pcie->mutex); @@ -159,8 +156,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; - was_hw_rfkill = iwl_is_rfkill_set(trans); - /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); @@ -191,9 +186,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); - /* stop and reset the on-board processor */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Upon stop, the IVAR table gets erased, so msi-x won't @@ -217,7 +210,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); clear_bit(STATUS_INT_ENABLED, &trans->status); clear_bit(STATUS_TPOWER_PMI, &trans->status); - clear_bit(STATUS_RFKILL, &trans->status); /* * Even if we stop the HW, we still want the RF kill @@ -225,26 +217,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) */ iwl_enable_rfkill_int(trans); - /* - * Check again since the RF kill state may have changed while - * all the interrupts were disabled, in this case we couldn't - * receive the RF kill interrupt and update the state in the - * op_mode. - * Don't call the op_mode if the rkfill state hasn't changed. - * This allows the op_mode to call stop_device from the rfkill - * notification without endless recursion. Under very rare - * circumstances, we might have a small recursion if the rfkill - * state changed exactly now while we were called from stop_device. - * This is very unlikely but can happen and is supported. - */ - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - else - clear_bit(STATUS_RFKILL, &trans->status); - if (hw_rfkill != was_hw_rfkill) - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - /* re-take ownership to prevent other users from stealing the device */ iwl_pcie_prepare_card_hw(trans); } @@ -252,9 +224,13 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool was_in_rfkill; mutex_lock(&trans_pcie->mutex); + trans_pcie->opmode_down = true; + was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status); _iwl_trans_pcie_gen2_stop_device(trans, low_power); + iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill); mutex_unlock(&trans_pcie->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 93cbc7a69bcd..92b3a55d0fbc 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -80,7 +80,7 @@ #include "iwl-prph.h" #include "iwl-scd.h" #include "iwl-agn-hw.h" -#include "iwl-fw-error-dump.h" +#include "fw/error-dump.h" #include "internal.h" #include "iwl-fh.h" @@ -224,9 +224,9 @@ void iwl_pcie_apm_config(struct iwl_trans *trans) pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap); trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; - dev_info(trans->dev, "L1 %sabled - LTR %sabled\n", - (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", - trans->ltr_enabled ? "En" : "Dis"); + IWL_DEBUG_POWER(trans, "L1 %sabled - LTR %sabled\n", + (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", + trans->ltr_enabled ? "En" : "Dis"); } /* @@ -236,7 +236,8 @@ void iwl_pcie_apm_config(struct iwl_trans *trans) */ static int iwl_pcie_apm_init(struct iwl_trans *trans) { - int ret = 0; + int ret; + IWL_DEBUG_INFO(trans, "Init card's basic functions\n"); /* @@ -245,7 +246,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) */ /* Disable L0S exit timer (platform NMI Work/Around) */ - if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); @@ -287,8 +288,8 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { - IWL_DEBUG_INFO(trans, "Failed to init the card\n"); - goto out; + IWL_ERR(trans, "Failed to init the card\n"); + return ret; } if (trans->cfg->host_interrupt_operation_mode) { @@ -336,8 +337,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) set_bit(STATUS_DEVICE_ENABLED, &trans->status); -out: - return ret; + return 0; } /* @@ -358,9 +358,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_XTAL_ON); - /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Set "initialization complete" bit to move adapter from @@ -401,12 +399,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) apmg_xtal_cfg_reg | SHR_APMG_XTAL_CFG_XTAL_ON_REQ); - /* - * Reset entire device again - do controller reset (results in - * SHRD_HW_RST). Turn MAC off before proceeding. - */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* Enable LP XTAL by indirect access through CSR */ apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG); @@ -448,9 +441,9 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) ~SHR_APMG_XTAL_CFG_XTAL_ON_REQ); } -int iwl_pcie_apm_stop_master(struct iwl_trans *trans) +void iwl_pcie_apm_stop_master(struct iwl_trans *trans) { - int ret = 0; + int ret; /* stop device's busmaster DMA activity */ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); @@ -462,8 +455,6 @@ int iwl_pcie_apm_stop_master(struct iwl_trans *trans) IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); IWL_DEBUG_INFO(trans, "stop master\n"); - - return ret; } static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) @@ -478,7 +469,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_WAKE_ME); - else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) { iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, @@ -501,9 +492,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) return; } - /* Reset the entire device */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Clear "initialization complete" bit to move adapter from @@ -516,13 +505,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) static int iwl_pcie_nic_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; /* nic_init */ spin_lock(&trans_pcie->irq_lock); - iwl_pcie_apm_init(trans); - + ret = iwl_pcie_apm_init(trans); spin_unlock(&trans_pcie->irq_lock); + if (ret) + return ret; + iwl_pcie_set_pwr(trans, false); iwl_op_mode_nic_config(trans->op_mode); @@ -892,7 +884,7 @@ monitor: if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), trans_pcie->fw_mon_phys >> dest->base_shift); - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) iwl_write_prph(trans, le32_to_cpu(dest->end_reg), (trans_pcie->fw_mon_phys + trans_pcie->fw_mon_size - 256) >> @@ -996,14 +988,24 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill = iwl_is_rfkill_set(trans); + bool prev = test_bit(STATUS_RFKILL_OPMODE, &trans->status); + bool report; - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - else - clear_bit(STATUS_RFKILL, &trans->status); + if (hw_rfkill) { + set_bit(STATUS_RFKILL_HW, &trans->status); + set_bit(STATUS_RFKILL_OPMODE, &trans->status); + } else { + clear_bit(STATUS_RFKILL_HW, &trans->status); + if (trans_pcie->opmode_down) + clear_bit(STATUS_RFKILL_OPMODE, &trans->status); + } - iwl_trans_pcie_rf_kill(trans, hw_rfkill); + report = test_bit(STATUS_RFKILL_OPMODE, &trans->status); + + if (prev != report) + iwl_trans_pcie_rf_kill(trans, report); return hw_rfkill; } @@ -1128,7 +1130,6 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie) static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - bool hw_rfkill, was_hw_rfkill; lockdep_assert_held(&trans_pcie->mutex); @@ -1137,8 +1138,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; - was_hw_rfkill = iwl_is_rfkill_set(trans); - /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); @@ -1173,9 +1172,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans, false); - /* stop and reset the on-board processor */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Upon stop, the IVAR table gets erased, so msi-x won't @@ -1199,7 +1196,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); clear_bit(STATUS_INT_ENABLED, &trans->status); clear_bit(STATUS_TPOWER_PMI, &trans->status); - clear_bit(STATUS_RFKILL, &trans->status); /* * Even if we stop the HW, we still want the RF kill @@ -1207,26 +1203,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) */ iwl_enable_rfkill_int(trans); - /* - * Check again since the RF kill state may have changed while - * all the interrupts were disabled, in this case we couldn't - * receive the RF kill interrupt and update the state in the - * op_mode. - * Don't call the op_mode if the rkfill state hasn't changed. - * This allows the op_mode to call stop_device from the rfkill - * notification without endless recursion. Under very rare - * circumstances, we might have a small recursion if the rfkill - * state changed exactly now while we were called from stop_device. - * This is very unlikely but can happen and is supported. - */ - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - else - clear_bit(STATUS_RFKILL, &trans->status); - if (hw_rfkill != was_hw_rfkill) - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - /* re-take ownership to prevent other users from stealing the device */ iwl_pcie_prepare_card_hw(trans); } @@ -1318,7 +1294,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); /* Load the given image to the HW */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) ret = iwl_pcie_load_given_ucode_8000(trans, fw); else ret = iwl_pcie_load_given_ucode(trans, fw); @@ -1339,12 +1315,45 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_pcie_tx_start(trans, scd_addr); } +void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans, + bool was_in_rfkill) +{ + bool hw_rfkill; + + /* + * Check again since the RF kill state may have changed while + * all the interrupts were disabled, in this case we couldn't + * receive the RF kill interrupt and update the state in the + * op_mode. + * Don't call the op_mode if the rkfill state hasn't changed. + * This allows the op_mode to call stop_device from the rfkill + * notification without endless recursion. Under very rare + * circumstances, we might have a small recursion if the rfkill + * state changed exactly now while we were called from stop_device. + * This is very unlikely but can happen and is supported. + */ + hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) { + set_bit(STATUS_RFKILL_HW, &trans->status); + set_bit(STATUS_RFKILL_OPMODE, &trans->status); + } else { + clear_bit(STATUS_RFKILL_HW, &trans->status); + clear_bit(STATUS_RFKILL_OPMODE, &trans->status); + } + if (hw_rfkill != was_in_rfkill) + iwl_trans_pcie_rf_kill(trans, hw_rfkill); +} + static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool was_in_rfkill; mutex_lock(&trans_pcie->mutex); + trans_pcie->opmode_down = true; + was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status); _iwl_trans_pcie_stop_device(trans, low_power); + iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill); mutex_unlock(&trans_pcie->mutex); } @@ -1355,6 +1364,8 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) lockdep_assert_held(&trans_pcie->mutex); + IWL_WARN(trans, "reporting RF_KILL (radio %s)\n", + state ? "disabled" : "enabled"); if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) { if (trans->cfg->gen2) _iwl_trans_pcie_gen2_stop_device(trans, true); @@ -1435,7 +1446,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); ret = iwl_poll_bit(trans, CSR_GP_CNTRL, @@ -1635,17 +1646,19 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) return err; } - /* Reset the entire device */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); - iwl_pcie_apm_init(trans); + err = iwl_pcie_apm_init(trans); + if (err) + return err; iwl_pcie_init_msix(trans_pcie); /* From now on, the op_mode will be kept updated about RF kill state */ iwl_enable_rfkill_int(trans); + trans_pcie->opmode_down = false; + /* Set is_down to false here so that...*/ trans_pcie->is_down = false; @@ -1822,7 +1835,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, /* this bit wakes up the NIC */ __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); /* @@ -2045,17 +2058,52 @@ void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) iwl_read_direct32(trans, FH_TX_TRB_REG(fifo))); } -static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) +static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq; - int cnt; unsigned long now = jiffies; + u8 wr_ptr; + + if (!test_bit(txq_idx, trans_pcie->queue_used)) + return -EINVAL; + + IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", txq_idx); + txq = trans_pcie->txq[txq_idx]; + wr_ptr = ACCESS_ONCE(txq->write_ptr); + + while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && + !time_after(jiffies, + now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { + u8 write_ptr = ACCESS_ONCE(txq->write_ptr); + + if (WARN_ONCE(wr_ptr != write_ptr, + "WR pointer moved while flushing %d -> %d\n", + wr_ptr, write_ptr)) + return -ETIMEDOUT; + usleep_range(1000, 2000); + } + + if (txq->read_ptr != txq->write_ptr) { + IWL_ERR(trans, + "fail to flush all tx fifo queues Q %d\n", txq_idx); + iwl_trans_pcie_log_scd_error(trans, txq); + return -ETIMEDOUT; + } + + IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", txq_idx); + + return 0; +} + +static int iwl_trans_pcie_wait_txqs_empty(struct iwl_trans *trans, u32 txq_bm) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int cnt; int ret = 0; /* waiting for all the tx frames complete might take a while */ for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { - u8 wr_ptr; if (cnt == trans_pcie->cmd_queue) continue; @@ -2064,34 +2112,11 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) if (!(BIT(cnt) & txq_bm)) continue; - IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt); - txq = trans_pcie->txq[cnt]; - wr_ptr = ACCESS_ONCE(txq->write_ptr); - - while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && - !time_after(jiffies, - now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { - u8 write_ptr = ACCESS_ONCE(txq->write_ptr); - - if (WARN_ONCE(wr_ptr != write_ptr, - "WR pointer moved while flushing %d -> %d\n", - wr_ptr, write_ptr)) - return -ETIMEDOUT; - usleep_range(1000, 2000); - } - - if (txq->read_ptr != txq->write_ptr) { - IWL_ERR(trans, - "fail to flush all tx fifo queues Q %d\n", cnt); - ret = -ETIMEDOUT; + ret = iwl_trans_pcie_wait_txq_empty(trans, cnt); + if (ret) break; - } - IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt); } - if (ret) - iwl_trans_pcie_log_scd_error(trans, txq); - return ret; } @@ -2393,17 +2418,12 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, struct iwl_trans *trans = file->private_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct isr_statistics *isr_stats = &trans_pcie->isr_stats; - - char buf[8]; - int buf_size; u32 reset_flag; + int ret; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%x", &reset_flag) != 1) - return -EFAULT; + ret = kstrtou32_from_user(user_buf, count, 16, &reset_flag); + if (ret) + return ret; if (reset_flag == 0) memset(isr_stats, 0, sizeof(*isr_stats)); @@ -2415,16 +2435,6 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_trans *trans = file->private_data; - char buf[8]; - int buf_size; - int csr; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &csr) != 1) - return -EFAULT; iwl_pcie_dump_csr(trans); @@ -2449,11 +2459,50 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_rfkill_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + char buf[100]; + int pos; + + pos = scnprintf(buf, sizeof(buf), "debug: %d\nhw: %d\n", + trans_pcie->debug_rfkill, + !(iwl_read32(trans, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_rfkill_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool old = trans_pcie->debug_rfkill; + int ret; + + ret = kstrtobool_from_user(user_buf, count, &trans_pcie->debug_rfkill); + if (ret) + return ret; + if (old == trans_pcie->debug_rfkill) + return count; + IWL_WARN(trans, "changing debug rfkill %d->%d\n", + old, trans_pcie->debug_rfkill); + iwl_pcie_handle_rfkill_irq(trans); + + return count; +} + DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_READ_FILE_OPS(tx_queue); DEBUGFS_WRITE_FILE_OPS(csr); +DEBUGFS_READ_WRITE_FILE_OPS(rfkill); /* Create the debugfs files and directories */ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) @@ -2465,6 +2514,7 @@ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(csr, dir, S_IWUSR); DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); + DEBUGFS_ADD_FILE(rfkill, dir, S_IWUSR | S_IRUSR); return 0; err: @@ -2563,8 +2613,15 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans, (*data)->len = cpu_to_le32(fh_regs_len); val = (void *)(*data)->data; - for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND; i += sizeof(u32)) - *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); + if (!trans->cfg->gen2) + for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND; + i += sizeof(u32)) + *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); + else + for (i = FH_MEM_LOWER_BOUND_GEN2; i < FH_MEM_UPPER_BOUND_GEN2; + i += sizeof(u32)) + *val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans, + i)); iwl_trans_release_nic_access(trans, &flags); @@ -2714,7 +2771,7 @@ static struct iwl_trans_dump_data trans->dbg_dest_tlv->end_shift; /* Make "end" point to the actual end */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 || + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000 || trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) end += (1 << trans->dbg_dest_tlv->end_shift); monitor_len = end - base; @@ -2740,7 +2797,12 @@ static struct iwl_trans_dump_data len += sizeof(*data) + IWL_CSR_TO_DUMP; /* FH registers */ - len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); + if (trans->cfg->gen2) + len += sizeof(*data) + + (FH_MEM_UPPER_BOUND_GEN2 - FH_MEM_LOWER_BOUND_GEN2); + else + len += sizeof(*data) + + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); if (dump_rbs) { /* Dump RBs is supported only for pre-9000 devices (1 queue) */ @@ -2754,6 +2816,13 @@ static struct iwl_trans_dump_data (PAGE_SIZE << trans_pcie->rx_page_order)); } + /* Paged memory for gen2 HW */ + if (trans->cfg->gen2) + for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++) + len += sizeof(*data) + + sizeof(struct iwl_fw_error_dump_paging) + + trans_pcie->init_dram.paging[i].size; + dump_data = vzalloc(len); if (!dump_data) return NULL; @@ -2793,6 +2862,28 @@ static struct iwl_trans_dump_data if (dump_rbs) len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); + /* Paged memory for gen2 HW */ + if (trans->cfg->gen2) { + for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++) { + struct iwl_fw_error_dump_paging *paging; + dma_addr_t addr = + trans_pcie->init_dram.paging[i].physical; + u32 page_len = trans_pcie->init_dram.paging[i].size; + + data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING); + data->len = cpu_to_le32(sizeof(*paging) + page_len); + paging = (void *)data->data; + paging->index = cpu_to_le32(i); + dma_sync_single_for_cpu(trans->dev, addr, page_len, + DMA_BIDIRECTIONAL); + memcpy(paging->data, + trans_pcie->init_dram.paging[i].block, page_len); + data = iwl_fw_error_next_data(data); + + len += sizeof(*data) + sizeof(*paging) + page_len; + } + } + len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); dump_data->len = len; @@ -2835,7 +2926,6 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans) .ref = iwl_trans_pcie_ref, \ .unref = iwl_trans_pcie_unref, \ .dump_data = iwl_trans_pcie_dump_data, \ - .wait_tx_queues_empty = iwl_trans_pcie_wait_txq_empty, \ .d3_suspend = iwl_trans_pcie_d3_suspend, \ .d3_resume = iwl_trans_pcie_d3_resume @@ -2865,6 +2955,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, + .wait_tx_queues_empty = iwl_trans_pcie_wait_txqs_empty, + .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, }; @@ -2884,6 +2976,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, .txq_free = iwl_trans_pcie_dyn_txq_free, + .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, @@ -2910,6 +3003,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->trans = trans; + trans_pcie->opmode_down = true; spin_lock_init(&trans_pcie->irq_lock); spin_lock_init(&trans_pcie->reg_lock); mutex_init(&trans_pcie->mutex); @@ -2988,7 +3082,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * "dash" value). To keep hw_rev backwards compatible - we'll store it * in the old format. */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) { unsigned long flags; trans->hw_rev = (trans->hw_rev & 0xfff0) | @@ -3032,6 +3126,17 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } + /* + * 9000-series integrated A-step has a problem with suspend/resume + * and sometimes even causes the whole platform to get stuck. This + * workaround makes the hardware not go into the problematic state. + */ + if (trans->cfg->integrated && + trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 && + CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP) + iwl_set_bit(trans, CSR_HOST_CHICKEN, + CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME); + trans->hw_rf_id = iwl_read32(trans, CSR_HW_RF_ID); iwl_pcie_set_interrupt_capa(pdev, trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 9c9bfbbabdf1..a3795ba0d7b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -49,6 +49,7 @@ * *****************************************************************************/ #include <linux/pm_runtime.h> +#include <net/tso.h> #include "iwl-debug.h" #include "iwl-csr.h" @@ -226,6 +227,143 @@ static int iwl_pcie_gen2_set_tb(struct iwl_trans *trans, return idx; } +static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, + struct sk_buff *skb, + struct iwl_tfh_tfd *tfd, int start_len, + u8 hdr_len, struct iwl_device_cmd *dev_cmd) +{ +#ifdef CONFIG_INET + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; + struct ieee80211_hdr *hdr = (void *)skb->data; + unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; + unsigned int mss = skb_shinfo(skb)->gso_size; + u16 length, iv_len, amsdu_pad; + u8 *start_hdr; + struct iwl_tso_hdr_page *hdr_page; + struct page **page_ptr; + struct tso_t tso; + + /* if the packet is protected, then it must be CCMP or GCMP */ + iv_len = ieee80211_has_protected(hdr->frame_control) ? + IEEE80211_CCMP_HDR_LEN : 0; + + trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), + &dev_cmd->hdr, start_len, 0); + + ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); + snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); + total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len; + amsdu_pad = 0; + + /* total amount of header we may need for this A-MSDU */ + hdr_room = DIV_ROUND_UP(total_len, mss) * + (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; + + /* Our device supports 9 segments at most, it will fit in 1 page */ + hdr_page = get_page_hdr(trans, hdr_room); + if (!hdr_page) + return -ENOMEM; + + get_page(hdr_page->page); + start_hdr = hdr_page->pos; + page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs); + *page_ptr = hdr_page->page; + memcpy(hdr_page->pos, skb->data + hdr_len, iv_len); + hdr_page->pos += iv_len; + + /* + * Pull the ieee80211 header + IV to be able to use TSO core, + * we will restore it for the tx_status flow. + */ + skb_pull(skb, hdr_len + iv_len); + + /* + * Remove the length of all the headers that we don't actually + * have in the MPDU by themselves, but that we duplicate into + * all the different MSDUs inside the A-MSDU. + */ + le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen); + + tso_start(skb, &tso); + + while (total_len) { + /* this is the data left for this subframe */ + unsigned int data_left = min_t(unsigned int, mss, total_len); + struct sk_buff *csum_skb = NULL; + unsigned int tb_len; + dma_addr_t tb_phys; + struct tcphdr *tcph; + u8 *iph, *subf_hdrs_start = hdr_page->pos; + + total_len -= data_left; + + memset(hdr_page->pos, 0, amsdu_pad); + hdr_page->pos += amsdu_pad; + amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen + + data_left)) & 0x3; + ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr)); + hdr_page->pos += ETH_ALEN; + ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr)); + hdr_page->pos += ETH_ALEN; + + length = snap_ip_tcp_hdrlen + data_left; + *((__be16 *)hdr_page->pos) = cpu_to_be16(length); + hdr_page->pos += sizeof(length); + + /* + * This will copy the SNAP as well which will be considered + * as MAC header. + */ + tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len); + iph = hdr_page->pos + 8; + tcph = (void *)(iph + ip_hdrlen); + + hdr_page->pos += snap_ip_tcp_hdrlen; + + tb_len = hdr_page->pos - start_hdr; + tb_phys = dma_map_single(trans->dev, start_hdr, + tb_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + dev_kfree_skb(csum_skb); + goto out_err; + } + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); + trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, tb_len); + /* add this subframe's headers' length to the tx_cmd */ + le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); + + /* prepare the start_hdr for the next subframe */ + start_hdr = hdr_page->pos; + + /* put the payload */ + while (data_left) { + tb_len = min_t(unsigned int, tso.size, data_left); + tb_phys = dma_map_single(trans->dev, tso.data, + tb_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + dev_kfree_skb(csum_skb); + goto out_err; + } + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); + trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data, + tb_len); + + data_left -= tb_len; + tso_build_data(skb, &tso, tb_len); + } + } + + /* re -add the WiFi header and IV */ + skb_push(skb, hdr_len + iv_len); + + return 0; + +out_err: +#endif + return -EINVAL; +} + static struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, @@ -238,15 +376,21 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); dma_addr_t tb_phys; + bool amsdu; int i, len, tb1_len, tb2_len, hdr_len; void *tb1_addr; memset(tfd, 0, sizeof(*tfd)); + amsdu = ieee80211_is_data_qos(hdr->frame_control) && + (*ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CTL_A_MSDU_PRESENT); + tb_phys = iwl_pcie_get_first_tb_dma(txq, txq->write_ptr); /* The first TB points to bi-directional DMA data */ - memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, - IWL_FIRST_TB_SIZE); + if (!amsdu) + memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + IWL_FIRST_TB_SIZE); iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE); @@ -262,7 +406,11 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, len = sizeof(struct iwl_tx_cmd_gen2) + sizeof(struct iwl_cmd_header) + ieee80211_hdrlen(hdr->frame_control) - IWL_FIRST_TB_SIZE; - tb1_len = ALIGN(len, 4); + /* do not align A-MSDU to dword as the subframe header aligns it */ + if (amsdu) + tb1_len = len; + else + tb1_len = ALIGN(len, 4); /* map the data for TB1 */ tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; @@ -271,8 +419,24 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, goto out_err; iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb1_len); - /* set up TFD's third entry to point to remainder of skb's head */ hdr_len = ieee80211_hdrlen(hdr->frame_control); + + if (amsdu) { + if (!iwl_pcie_gen2_build_amsdu(trans, skb, tfd, + tb1_len + IWL_FIRST_TB_SIZE, + hdr_len, dev_cmd)) + goto out_err; + + /* + * building the A-MSDU might have changed this data, so memcpy + * it now + */ + memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + IWL_FIRST_TB_SIZE); + return tfd; + } + + /* set up TFD's third entry to point to remainder of skb's head */ tb2_len = skb_headlen(skb) - hdr_len; if (tb2_len > 0) { @@ -303,10 +467,8 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, } trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, - IWL_FIRST_TB_SIZE + tb1_len, - skb->data + hdr_len, tb2_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len, - skb->len - hdr_len); + IWL_FIRST_TB_SIZE + tb1_len, hdr_len); + trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); return tfd; @@ -699,7 +861,7 @@ static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans, } if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); ret = -ERFKILL; goto cancel; @@ -736,7 +898,7 @@ int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", cmd->id); return -ERFKILL; @@ -912,7 +1074,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, rsp = (void *)hcmd.resp_pkt->data; qid = le16_to_cpu(rsp->queue_number); - if (qid > ARRAY_SIZE(trans_pcie->txq)) { + if (qid >= ARRAY_SIZE(trans_pcie->txq)) { WARN_ONCE(1, "queue index %d unsupported", qid); ret = -EIO; goto error_free_resp; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 386950a2d616..de50418adae5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -762,7 +762,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); /* Enable L1-Active */ - if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } @@ -1277,13 +1277,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) -void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, +bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txq[txq_id]; int fifo = -1; + bool scd_bug = false; if (test_and_set_bit(txq_id, trans_pcie->queue_used)) WARN_ONCE(1, "queue %d already used - expect issues", txq_id); @@ -1324,6 +1325,23 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, ssn = txq->read_ptr; } + } else { + /* + * If we need to move the SCD write pointer by steps of + * 0x40, 0x80 or 0xc0, it gets stuck. Avoids this and let + * the op_mode know by returning true later. + * Do this only in case cfg is NULL since this trick can + * be done only if we have DQA enabled which is true for mvm + * only. And mvm never sets a cfg pointer. + * This is really ugly, but this is the easiest way out for + * this sad hardware issue. + * This bug has been fixed on devices 9000 and up. + */ + scd_bug = !trans->cfg->mq_rx_supported && + !((ssn - txq->write_ptr) & 0x3f) && + (ssn != txq->write_ptr); + if (scd_bug) + ssn++; } /* Place first TFD at index corresponding to start sequence number. @@ -1344,10 +1362,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + SCD_QUEUE_CTX_REG2_VAL(WIN_SIZE, frame_limit) | + SCD_QUEUE_CTX_REG2_VAL(FRAME_LIMIT, frame_limit)); /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */ iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), @@ -1369,6 +1385,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, "Activate queue %d WrPtr: %d\n", txq_id, ssn & 0xff); } + + return scd_bug; } void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, @@ -1708,7 +1726,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); - u8 group_id = iwl_cmd_groupid(pkt->hdr.group_id); + u8 group_id; u32 cmd_id; int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -1734,6 +1752,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, cmd_index = get_cmd_index(txq, index); cmd = txq->entries[cmd_index].cmd; meta = &txq->entries[cmd_index].meta; + group_id = cmd->hdr.group_id; cmd_id = iwl_cmd_id(cmd->hdr.cmd, group_id, 0); iwl_pcie_tfd_unmap(trans, meta, txq, index); @@ -1876,7 +1895,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, } if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); ret = -ERFKILL; goto cancel; @@ -1913,7 +1932,7 @@ cancel: int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", cmd->id); return -ERFKILL; @@ -1980,15 +1999,13 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), trans_pcie->tfd_size, &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, - skb->data + hdr_len, tb2_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, - hdr_len, skb->len - hdr_len); + hdr_len); + trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); return 0; } #ifdef CONFIG_INET -static struct iwl_tso_hdr_page * -get_page_hdr(struct iwl_trans *trans, size_t len) +struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->tso_hdr_page); @@ -2055,8 +2072,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, trace_iwlwifi_dev_tx(trans->dev, skb, iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), trans_pcie->tfd_size, - &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, - NULL, 0); + &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, 0); ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); @@ -2141,8 +2157,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, htons(ETH_P_IPV6), data_left); - memcpy(skb_put(csum_skb, tcp_hdrlen(skb)), - tcph, tcp_hdrlen(skb)); + skb_put_data(csum_skb, tcph, tcp_hdrlen(skb)); skb_reset_transport_header(csum_skb); csum_skb->csum_start = (unsigned char *)tcp_hdr(csum_skb) - @@ -2176,7 +2191,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, dma_addr_t tb_phys; if (trans_pcie->sw_csum_tx) - memcpy(skb_put(csum_skb, size), tso.data, size); + skb_put_data(csum_skb, tso.data, size); tb_phys = dma_map_single(trans->dev, tso.data, size, DMA_TO_DEVICE); diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c index 34dbddbf3f9b..6d8b64ca1a63 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c @@ -131,8 +131,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, if (prism_header == 1) { struct linux_wlan_ng_prism_hdr *hdr; - hdr = (struct linux_wlan_ng_prism_hdr *) - skb_push(skb, phdrlen); + hdr = skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->msgcode = LWNG_CAP_DID_BASE; hdr->msglen = sizeof(*hdr); @@ -153,8 +152,7 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d #undef LWNG_SETVAL } else if (prism_header == 2) { struct linux_wlan_ng_cap_hdr *hdr; - hdr = (struct linux_wlan_ng_cap_hdr *) - skb_push(skb, phdrlen); + hdr = skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->version = htonl(LWNG_CAPHDR_VERSION); hdr->length = htonl(phdrlen); @@ -172,7 +170,7 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d hdr->encoding = htonl(1); /* cck */ } else if (prism_header == 3) { struct hostap_radiotap_rx *hdr; - hdr = (struct hostap_radiotap_rx *)skb_push(skb, phdrlen); + hdr = skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->hdr.it_len = cpu_to_le16(phdrlen); hdr->hdr.it_present = diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c index 055e11d353ca..c1b10d5117ad 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c @@ -242,7 +242,7 @@ netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); if (use_wds == WDS_OWN_FRAME) { - memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN); + skb_put_data(skb, &hdr.addr4, ETH_ALEN); } iface->stats.tx_packets++; diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c index c995ace153ee..eb9cd6fa9c4d 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ap.c @@ -998,11 +998,9 @@ static void prism2_send_mgmt(struct net_device *dev, fc = type_subtype; hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); - hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); + hdr = skb_put_zero(skb, hdrlen); if (body) - memcpy(skb_put(skb, body_len), body, body_len); - - memset(hdr, 0, hdrlen); + skb_put_data(skb, body, body_len); /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 * tx_control instead of using local->tx_control */ @@ -1325,8 +1323,7 @@ static char * ap_auth_make_challenge(struct ap_data *ap) } skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); - memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, - WLAN_AUTH_CHALLENGE_LEN); + skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN); if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { dev_kfree_skb(skb); kfree(tmpbuf); @@ -2364,7 +2361,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) return; } - hdr = (struct ieee80211_hdr *) skb_put(skb, 16); + hdr = skb_put(skb, 16); /* Generate a fake pspoll frame to start packet delivery */ hdr->frame_control = cpu_to_le16( diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index 04dfd040a650..72b46eaf3de2 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -190,7 +190,7 @@ static inline void __hostap_cmd_queue_free(local_info_t *local, } } - if (atomic_dec_and_test(&entry->usecnt) && entry->del_req) + if (refcount_dec_and_test(&entry->usecnt) && entry->del_req) kfree(entry); } @@ -228,7 +228,7 @@ static void prism2_clear_cmd_queue(local_info_t *local) spin_lock_irqsave(&local->cmdlock, flags); list_for_each_safe(ptr, n, &local->cmd_queue) { entry = list_entry(ptr, struct hostap_cmd_queue, list); - atomic_inc(&entry->usecnt); + refcount_inc(&entry->usecnt); printk(KERN_DEBUG "%s: removed pending cmd_queue entry " "(type=%d, cmd=0x%04x, param0=0x%04x)\n", local->dev->name, entry->type, entry->cmd, @@ -350,7 +350,7 @@ static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, if (entry == NULL) return -ENOMEM; - atomic_set(&entry->usecnt, 1); + refcount_set(&entry->usecnt, 1); entry->type = CMD_SLEEP; entry->cmd = cmd; entry->param0 = param0; @@ -516,7 +516,7 @@ static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, if (entry == NULL) return -ENOMEM; - atomic_set(&entry->usecnt, 1); + refcount_set(&entry->usecnt, 1); entry->type = CMD_CALLBACK; entry->cmd = cmd; entry->param0 = param0; @@ -666,7 +666,7 @@ static void prism2_cmd_ev(struct net_device *dev) if (!list_empty(&local->cmd_queue)) { entry = list_entry(local->cmd_queue.next, struct hostap_cmd_queue, list); - atomic_inc(&entry->usecnt); + refcount_inc(&entry->usecnt); list_del_init(&entry->list); local->cmd_queue_len--; @@ -718,7 +718,7 @@ static void prism2_cmd_ev(struct net_device *dev) entry = NULL; } if (entry) - atomic_inc(&entry->usecnt); + refcount_inc(&entry->usecnt); } spin_unlock(&local->cmdlock); @@ -2005,7 +2005,7 @@ static void prism2_rx(local_info_t *local) goto rx_dropped; } skb->dev = dev; - memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len); + skb_put_data(skb, &rxdesc, hdr_len); if (len > 0) res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len); @@ -2209,9 +2209,9 @@ static void hostap_tx_callback(local_info_t *local, return; } - memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen); + skb_put_data(skb, (void *)&txdesc->frame_control, hdrlen); if (payload) - memcpy(skb_put(skb, len), payload, len); + skb_put_data(skb, payload, len); skb->dev = local->dev; skb_reset_mac_header(skb); @@ -2362,8 +2362,7 @@ static void prism2_txexc(local_info_t *local) struct sk_buff *skb; skb = dev_alloc_skb(sizeof(txdesc)); if (skb) { - memcpy(skb_put(skb, sizeof(txdesc)), &txdesc, - sizeof(txdesc)); + skb_put_data(skb, &txdesc, sizeof(txdesc)); skb_queue_tail(&local->sta_tx_exc_list, skb); tasklet_schedule(&local->sta_tx_exc_tasklet); } @@ -2460,7 +2459,7 @@ static void prism2_info(local_info_t *local) goto out; } - memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info)); + skb_put_data(skb, &info, sizeof(info)); if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) { spin_unlock(&local->baplock); diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c index 1372b20f931e..a3c066f90afc 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ b/drivers/net/wireless/intersil/hostap/hostap_main.c @@ -1039,15 +1039,13 @@ int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, if (skb == NULL) return -ENOMEM; - mgmt = (struct hostap_ieee80211_mgmt *) - skb_put(skb, IEEE80211_MGMT_HDR_LEN); - memset(mgmt, 0, IEEE80211_MGMT_HDR_LEN); + mgmt = skb_put_zero(skb, IEEE80211_MGMT_HDR_LEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); memcpy(mgmt->da, dst, ETH_ALEN); memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, dst, ETH_ALEN); if (body) - memcpy(skb_put(skb, bodylen), body, bodylen); + skb_put_data(skb, body, bodylen); meta = (struct hostap_skb_tx_data *) skb->cb; memset(meta, 0, sizeof(*meta)); diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h index ca25283e1c92..5352adb94d50 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h +++ b/drivers/net/wireless/intersil/hostap/hostap_wlan.h @@ -6,6 +6,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/mutex.h> +#include <linux/refcount.h> #include <net/iw_handler.h> #include <net/ieee80211_radiotap.h> #include <net/lib80211.h> @@ -557,7 +558,7 @@ struct hostap_cmd_queue { u16 resp0, res; volatile int issued, issuing; - atomic_t usecnt; + refcount_t usecnt; int del_req; }; diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c index d9128bb25e85..28dac36d7c4c 100644 --- a/drivers/net/wireless/intersil/orinoco/main.c +++ b/drivers/net/wireless/intersil/orinoco/main.c @@ -396,7 +396,7 @@ int orinoco_process_xmit_skb(struct sk_buff *skb, memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); /* Make room for the new header, and copy it in */ - eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD); + eh = skb_push(skb, ENCAPS_OVERHEAD); memcpy(eh, &hdr, sizeof(hdr)); } @@ -792,7 +792,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, } /* Copy the 802.11 header to the skb */ - memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen); + skb_put_data(skb, &(desc->frame_ctl), hdrlen); skb_reset_mac_header(skb); /* If any, copy the data from the card to the skb */ @@ -1029,11 +1029,10 @@ static void orinoco_rx(struct net_device *dev, /* These indicate a SNAP within 802.2 LLC within 802.11 frame which we'll need to de-encapsulate to the original EthernetII frame. */ - hdr = (struct ethhdr *)skb_push(skb, - ETH_HLEN - ENCAPS_OVERHEAD); + hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); } else { /* 802.3 frame - prepend 802.3 header as is */ - hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); + hdr = skb_push(skb, ETH_HLEN); hdr->h_proto = htons(length); } memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 132f5fbda58b..c84fd8490601 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -64,6 +64,7 @@ #include <linux/etherdevice.h> #include <linux/wireless.h> #include <linux/firmware.h> +#include <linux/refcount.h> #include "mic.h" #include "orinoco.h" @@ -268,7 +269,7 @@ enum ezusb_state { struct request_context { struct list_head list; - atomic_t refcount; + refcount_t refcount; struct completion done; /* Signals that CTX is dead */ int killed; struct urb *outurb; /* OUT for req pkt */ @@ -298,7 +299,7 @@ static inline u8 ezusb_reply_inc(u8 count) static void ezusb_request_context_put(struct request_context *ctx) { - if (!atomic_dec_and_test(&ctx->refcount)) + if (!refcount_dec_and_test(&ctx->refcount)) return; WARN_ON(!ctx->done.done); @@ -328,7 +329,7 @@ static void ezusb_request_timerfn(u_long _ctx) } else { ctx->state = EZUSB_CTX_RESP_TIMEOUT; dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n"); - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); ctx->killed = 1; ezusb_ctx_complete(ctx); ezusb_request_context_put(ctx); @@ -361,7 +362,7 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv, ctx->out_rid = out_rid; ctx->in_rid = in_rid; - atomic_set(&ctx->refcount, 1); + refcount_set(&ctx->refcount, 1); init_completion(&ctx->done); setup_timer(&ctx->timer, ezusb_request_timerfn, (u_long)ctx); @@ -469,7 +470,7 @@ static void ezusb_req_queue_run(struct ezusb_priv *upriv) list_move_tail(&ctx->list, &upriv->req_active); if (ctx->state == EZUSB_CTX_QUEUED) { - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); result = usb_submit_urb(ctx->outurb, GFP_ATOMIC); if (result) { ctx->state = EZUSB_CTX_REQSUBMIT_FAIL; @@ -507,7 +508,7 @@ static void ezusb_req_enqueue_run(struct ezusb_priv *upriv, spin_unlock_irqrestore(&upriv->req_lock, flags); goto done; } - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); list_add_tail(&ctx->list, &upriv->req_pending); spin_unlock_irqrestore(&upriv->req_lock, flags); @@ -1477,7 +1478,7 @@ static inline void ezusb_delete(struct ezusb_priv *upriv) int err; ctx = list_entry(item, struct request_context, list); - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; err = usb_unlink_urb(ctx->outurb); diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index 4ac6764f4897..52c095c7765f 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -176,8 +176,9 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) * keeping a extra list for uploaded keys. */ - priv->used_rxkeys = kzalloc(BITS_TO_LONGS( - priv->rx_keycache_size), GFP_KERNEL); + priv->used_rxkeys = kcalloc(BITS_TO_LONGS(priv->rx_keycache_size), + sizeof(long), + GFP_KERNEL); if (!priv->used_rxkeys) return -ENOMEM; @@ -205,7 +206,7 @@ static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags, return NULL; skb_reserve(skb, priv->tx_hdr_len); - hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); hdr->flags = cpu_to_le16(hdr_flags); hdr->len = cpu_to_le16(payload_len); hdr->type = cpu_to_le16(type); @@ -235,8 +236,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, mutex_lock(&priv->eeprom_mutex); priv->eeprom = buf; - eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, - eeprom_hdr_size + len); + eeprom_hdr = skb_put(skb, eeprom_hdr_size + len); if (priv->fw_var < 0x509) { eeprom_hdr->v1.offset = cpu_to_le16(offset); @@ -272,7 +272,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set) if (unlikely(!skb)) return -ENOMEM; - tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim = skb_put(skb, sizeof(*tim)); tim->count = 1; tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid); p54_tx(priv, skb); @@ -289,7 +289,7 @@ int p54_sta_unlock(struct p54_common *priv, u8 *addr) if (unlikely(!skb)) return -ENOMEM; - sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + sta = skb_put(skb, sizeof(*sta)); memcpy(sta->addr, addr, ETH_ALEN); p54_tx(priv, skb); return 0; @@ -309,7 +309,7 @@ int p54_tx_cancel(struct p54_common *priv, __le32 req_id) if (unlikely(!skb)) return -ENOMEM; - cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel = skb_put(skb, sizeof(*cancel)); cancel->req_id = req_id; p54_tx(priv, skb); return 0; @@ -326,7 +326,7 @@ int p54_setup_mac(struct p54_common *priv) if (!skb) return -ENOMEM; - setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + setup = skb_put(skb, sizeof(*setup)); if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) { switch (priv->mode) { case NL80211_IFTYPE_STATION: @@ -412,18 +412,18 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) if (!skb) return -ENOMEM; - head = (struct p54_scan_head *) skb_put(skb, sizeof(*head)); + head = skb_put(skb, sizeof(*head)); memset(head->scan_params, 0, sizeof(head->scan_params)); head->mode = cpu_to_le16(mode); head->dwell = cpu_to_le16(dwell); head->freq = freq; if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - __le16 *pa_power_points = (__le16 *) skb_put(skb, 2); + __le16 *pa_power_points = skb_put(skb, 2); *pa_power_points = cpu_to_le16(0x0c); } - iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal)); + iq_autocal = skb_put(skb, sizeof(*iq_autocal)); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) continue; @@ -436,9 +436,9 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) goto err; if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) - body = (void *) skb_put(skb, sizeof(body->longbow)); + body = skb_put(skb, sizeof(body->longbow)); else - body = (void *) skb_put(skb, sizeof(body->normal)); + body = skb_put(skb, sizeof(body->normal)); for (i = 0; i < priv->output_limit->entries; i++) { __le16 *entry_freq = (void *) (priv->output_limit->data + @@ -499,25 +499,25 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) goto err; if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) { - rate = (void *) skb_put(skb, sizeof(*rate)); + rate = skb_put(skb, sizeof(*rate)); rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); for (i = 0; i < sizeof(rate->rts_rates); i++) rate->rts_rates[i] = i; } - rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); + rssi = skb_put(skb, sizeof(*rssi)); rssi_data = p54_rssi_find(priv, le16_to_cpu(freq)); rssi->mul = cpu_to_le16(rssi_data->mul); rssi->add = cpu_to_le16(rssi_data->add); if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { /* Longbow frontend needs ever more */ - rssi = (void *) skb_put(skb, sizeof(*rssi)); + rssi = skb_put(skb, sizeof(*rssi)); rssi->mul = cpu_to_le16(rssi_data->longbow_unkn); rssi->add = cpu_to_le16(rssi_data->longbow_unk2); } if (priv->fw_var >= 0x509) { - rate = (void *) skb_put(skb, sizeof(*rate)); + rate = skb_put(skb, sizeof(*rate)); rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); for (i = 0; i < sizeof(rate->rts_rates); i++) rate->rts_rates[i] = i; @@ -549,7 +549,7 @@ int p54_set_leds(struct p54_common *priv) if (unlikely(!skb)) return -ENOMEM; - led = (struct p54_led *) skb_put(skb, sizeof(*led)); + led = skb_put(skb, sizeof(*led)); led->flags = cpu_to_le16(0x0003); led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); led->delay[0] = cpu_to_le16(1); @@ -569,7 +569,7 @@ int p54_set_edcf(struct p54_common *priv) if (unlikely(!skb)) return -ENOMEM; - edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); + edcf = skb_put(skb, sizeof(*edcf)); if (priv->use_short_slot) { edcf->slottime = 9; edcf->sifs = 0x10; @@ -614,7 +614,7 @@ int p54_set_ps(struct p54_common *priv) if (!skb) return -ENOMEM; - psm = (struct p54_psm *)skb_put(skb, sizeof(*psm)); + psm = skb_put(skb, sizeof(*psm)); psm->mode = cpu_to_le16(mode); psm->aid = cpu_to_le16(priv->aid); for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) { @@ -643,7 +643,7 @@ int p54_init_xbow_synth(struct p54_common *priv) if (unlikely(!skb)) return -ENOMEM; - xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); + xbow = skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); @@ -663,7 +663,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len, if (unlikely(!skb)) return -ENOMEM; - rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey = skb_put(skb, sizeof(*rxkey)); rxkey->entry = slot; rxkey->key_id = idx; rxkey->key_type = algo; @@ -743,7 +743,7 @@ int p54_set_groupfilter(struct p54_common *priv) if (!skb) return -ENOMEM; - grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); + grp = skb_put(skb, sizeof(*grp)); on = !(priv->filter_flags & FIF_ALLMULTI) && (priv->mc_maclist_num > 0 && diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index 7ab2f43ab425..e41bf042352e 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -372,9 +372,9 @@ static int p54spi_rx(struct p54s_priv *priv) } if (len <= READAHEAD_SZ) { - memcpy(skb_put(skb, len), rx_head + 1, len); + skb_put_data(skb, rx_head + 1, len); } else { - memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ); + skb_put_data(skb, rx_head + 1, READAHEAD_SZ); p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len - READAHEAD_SZ), len - READAHEAD_SZ); diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 5e1c91a80c58..3a4214d362ff 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -815,8 +815,8 @@ void p54_tx_80211(struct ieee80211_hw *dev, } } - txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); + txhdr = skb_push(skb, sizeof(*txhdr) + padding); + hdr = skb_push(skb, sizeof(*hdr)); if (padding) hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; @@ -905,13 +905,13 @@ void p54_tx_80211(struct ieee80211_hw *dev, if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { /* reserve space for the MIC key */ len += 8; - memcpy(skb_put(skb, 8), &(info->control.hw_key->key - [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + skb_put_data(skb, + &(info->control.hw_key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), + 8); } /* reserve some space for ICV */ len += info->control.hw_key->icv_len; - memset(skb_put(skb, info->control.hw_key->icv_len), 0, - info->control.hw_key->icv_len); + skb_put_zero(skb, info->control.hw_key->icv_len); } else { txhdr->key_type = 0; txhdr->key_len = 0; diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.c b/drivers/net/wireless/intersil/prism54/islpci_eth.c index d83f6332019e..9b0ded733294 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.c +++ b/drivers/net/wireless/intersil/prism54/islpci_eth.c @@ -276,10 +276,7 @@ islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb) } /* make room for the new header and fill it. */ - avs = - (struct avs_80211_1_header *) skb_push(*skb, - sizeof (struct - avs_80211_1_header)); + avs = skb_push(*skb, sizeof(struct avs_80211_1_header)); avs->version = cpu_to_be32(P80211CAPTURE_VERSION); avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c854a557998b..c8852acc1462 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -650,7 +650,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) skb = dev_alloc_skb(sizeof(*pspoll)); if (!skb) return; - pspoll = (void *) skb_put(skb, sizeof(*pspoll)); + pspoll = skb_put(skb, sizeof(*pspoll)); pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM); @@ -681,7 +681,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, skb = dev_alloc_skb(sizeof(*hdr)); if (!skb) return; - hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); + hdr = skb_put(skb, sizeof(*hdr) - ETH_ALEN); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | (ps ? IEEE80211_FCTL_PM : 0)); @@ -848,7 +848,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, if (skb == NULL) return; - hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr)); + hdr = skb_push(skb, sizeof(*hdr)); hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; hdr->hdr.it_pad = 0; hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); @@ -892,7 +892,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, if (skb == NULL) return; - hdr = (struct hwsim_radiotap_ack_hdr *) skb_put(skb, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; hdr->hdr.it_pad = 0; hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); @@ -904,7 +904,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, flags = IEEE80211_CHAN_2GHZ; hdr->rt_chbitmask = cpu_to_le16(flags); - hdr11 = (struct ieee80211_hdr *) skb_put(skb, 10); + hdr11 = skb_put(skb, 10); hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK); hdr11->duration_id = cpu_to_le16(0); @@ -1146,7 +1146,7 @@ static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) * Note that this code requires the headroom in the SKB * that was allocated earlier. */ - rtap = (void *)skb_push(skb, sizeof(*rtap) + 8 + 4); + rtap = skb_push(skb, sizeof(*rtap) + 8 + 4); rtap->oui[0] = HWSIM_RADIOTAP_OUI[0]; rtap->oui[1] = HWSIM_RADIOTAP_OUI[1]; rtap->oui[2] = HWSIM_RADIOTAP_OUI[2]; @@ -2020,8 +2020,7 @@ static void hw_scan_work(struct work_struct *work) memcpy(mgmt->bssid, req->bssid, ETH_ALEN); if (req->ie_len) - memcpy(skb_put(probe, req->ie_len), req->ie, - req->ie_len); + skb_put_data(probe, req->ie, req->ie_len); local_bh_disable(); mac80211_hwsim_tx_frame(hwsim->hw, probe, @@ -3021,7 +3020,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, goto err; /* Copy the data */ - memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len); + skb_put_data(skb, frame_data, frame_data_len); data2 = get_hwsim_data_ref_from_addr(dst); if (!data2) diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index a0463fef79b0..71ba2c8d09b5 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -443,17 +443,12 @@ static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy, struct lbs_private *priv = wiphy_priv(wiphy); int ret = -ENOTSUPP; - lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", - chandef->chan->center_freq, - cfg80211_get_chandef_type(chandef)); - if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) goto out; ret = lbs_set_channel(priv, chandef->chan->hw_value); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -464,16 +459,12 @@ static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy, struct lbs_private *priv = wiphy_priv(wiphy); int ret = -ENOTSUPP; - lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d", - netdev_name(netdev), channel->center_freq); - if (netdev != priv->mesh_dev) goto out; ret = lbs_mesh_set_channel(priv, channel->hw_value); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -512,8 +503,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, int i; int ret = -EILSEQ; - lbs_deb_enter(LBS_DEB_CFG80211); - bsssize = get_unaligned_le16(&scanresp->bssdescriptsize); lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n", @@ -665,7 +654,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, ret = 0; done: - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } @@ -693,11 +681,9 @@ static void lbs_scan_worker(struct work_struct *work) int last_channel; int running, carrier; - lbs_deb_enter(LBS_DEB_SCAN); - scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL); if (scan_cmd == NULL) - goto out_no_scan_cmd; + return; /* prepare fixed part of scan command */ scan_cmd->bsstype = CMD_BSS_TYPE_ANY; @@ -766,16 +752,11 @@ static void lbs_scan_worker(struct work_struct *work) lbs_deb_scan("scan: waking up waiters\n"); wake_up_all(&priv->scan_q); } - - out_no_scan_cmd: - lbs_deb_leave(LBS_DEB_SCAN); } static void _internal_start_scan(struct lbs_private *priv, bool internal, struct cfg80211_scan_request *request) { - lbs_deb_enter(LBS_DEB_CFG80211); - lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n", request->n_ssids, request->n_channels, request->ie_len); @@ -785,8 +766,6 @@ static void _internal_start_scan(struct lbs_private *priv, bool internal, queue_delayed_work(priv->work_thread, &priv->scan_work, msecs_to_jiffies(50)); - - lbs_deb_leave(LBS_DEB_CFG80211); } /* @@ -815,8 +794,6 @@ static int lbs_cfg_scan(struct wiphy *wiphy, struct lbs_private *priv = wiphy_priv(wiphy); int ret = 0; - lbs_deb_enter(LBS_DEB_CFG80211); - if (priv->scan_req || delayed_work_pending(&priv->scan_work)) { /* old scan request not yet processed */ ret = -EAGAIN; @@ -829,7 +806,6 @@ static int lbs_cfg_scan(struct wiphy *wiphy, ret = -EIO; out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -843,18 +819,12 @@ static int lbs_cfg_scan(struct wiphy *wiphy, void lbs_send_disconnect_notification(struct lbs_private *priv, bool locally_generated) { - lbs_deb_enter(LBS_DEB_CFG80211); - cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated, GFP_KERNEL); - - lbs_deb_leave(LBS_DEB_CFG80211); } void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) { - lbs_deb_enter(LBS_DEB_CFG80211); - cfg80211_michael_mic_failure(priv->dev, priv->assoc_bss, event == MACREG_INT_CODE_MIC_ERR_MULTICAST ? @@ -863,8 +833,6 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) -1, NULL, GFP_KERNEL); - - lbs_deb_leave(LBS_DEB_CFG80211); } @@ -883,8 +851,6 @@ static int lbs_remove_wep_keys(struct lbs_private *priv) struct cmd_ds_802_11_set_wep cmd; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.keyindex = cpu_to_le16(priv->wep_tx_key); @@ -892,7 +858,6 @@ static int lbs_remove_wep_keys(struct lbs_private *priv) ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -905,8 +870,6 @@ static int lbs_set_wep_keys(struct lbs_private *priv) int i; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - /* * command 13 00 * size 50 00 @@ -956,7 +919,6 @@ static int lbs_set_wep_keys(struct lbs_private *priv) ret = lbs_remove_wep_keys(priv); } - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -969,8 +931,6 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable) struct cmd_ds_802_11_enable_rsn cmd; int ret; - lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable); - /* * cmd 2f 00 * size 0c 00 @@ -986,7 +946,6 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable) ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -1014,8 +973,6 @@ static int lbs_set_key_material(struct lbs_private *priv, struct cmd_key_material cmd; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - /* * Example for WPA (TKIP): * @@ -1044,7 +1001,6 @@ static int lbs_set_key_material(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -1061,8 +1017,6 @@ static int lbs_set_authtype(struct lbs_private *priv, struct cmd_ds_802_11_authenticate cmd; int ret; - lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type); - /* * cmd 11 00 * size 19 00 @@ -1085,7 +1039,6 @@ static int lbs_set_authtype(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); done: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1116,8 +1069,6 @@ static int lbs_associate(struct lbs_private *priv, u8 *pos; u8 *tmp; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!cmd) { ret = -ENOMEM; goto done; @@ -1262,7 +1213,6 @@ static int lbs_associate(struct lbs_private *priv, kfree(cmd); done: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1329,8 +1279,6 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!sme->bssid) { struct cfg80211_scan_request *creq; @@ -1442,7 +1390,6 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, done: if (bss) cfg80211_put_bss(wiphy, bss); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1478,8 +1425,6 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); - /* store for lbs_cfg_ret_disconnect() */ priv->disassoc_reason = reason_code; @@ -1496,8 +1441,6 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy, if (netdev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - if (key_index != priv->wep_tx_key) { lbs_deb_assoc("set_default_key: to %d\n", key_index); priv->wep_tx_key = key_index; @@ -1520,8 +1463,6 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, if (netdev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", params->cipher, mac_addr); lbs_deb_assoc("add_key: key index %d, key len %d\n", @@ -1575,8 +1516,6 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr) { - lbs_deb_enter(LBS_DEB_CFG80211); - lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n", key_index, mac_addr); @@ -1619,8 +1558,6 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, int ret; size_t i; - lbs_deb_enter(LBS_DEB_CFG80211); - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) | BIT(NL80211_STA_INFO_TX_PACKETS) | BIT(NL80211_STA_INFO_RX_BYTES) | @@ -1675,15 +1612,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, return -EOPNOTSUPP; } - lbs_deb_enter(LBS_DEB_CFG80211); - if (priv->iface_running) ret = lbs_set_iface_type(priv, type); if (!ret) priv->wdev->iftype = type; - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1713,8 +1647,6 @@ static void lbs_join_post(struct lbs_private *priv, u8 *fake = fake_ie; struct cfg80211_bss *bss; - lbs_deb_enter(LBS_DEB_CFG80211); - /* * For cfg80211_inform_bss, we'll need a fake IE, as we can't get * the real IE from the firmware. So we fabricate a fake IE based on @@ -1777,8 +1709,6 @@ static void lbs_join_post(struct lbs_private *priv, netif_carrier_on(priv->dev); if (!priv->tx_pending_len) netif_wake_queue(priv->dev); - - lbs_deb_leave(LBS_DEB_CFG80211); } static int lbs_ibss_join_existing(struct lbs_private *priv, @@ -1790,8 +1720,6 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, u8 preamble = RADIO_PREAMBLE_SHORT; int ret = 0; - lbs_deb_enter(LBS_DEB_CFG80211); - /* TODO: set preamble based on scan result */ ret = lbs_set_radio(priv, preamble, 1); if (ret) @@ -1888,7 +1816,6 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, lbs_join_post(priv, params, bss->bssid, bss->capability); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1904,8 +1831,6 @@ static int lbs_ibss_start_new(struct lbs_private *priv, int ret = 0; u16 capability; - lbs_deb_enter(LBS_DEB_CFG80211); - ret = lbs_set_radio(priv, preamble, 1); if (ret) goto out; @@ -1975,7 +1900,6 @@ static int lbs_ibss_start_new(struct lbs_private *priv, lbs_join_post(priv, params, resp->bssid, capability); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1990,8 +1914,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!params->chandef.chan) { ret = -ENOTSUPP; goto out; @@ -2015,7 +1937,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -2029,8 +1950,6 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); @@ -2038,7 +1957,6 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */ lbs_mac_event_disconnected(priv, true); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -2114,8 +2032,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev) int ret = 0; struct wireless_dev *wdev; - lbs_deb_enter(LBS_DEB_CFG80211); - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!wdev) return ERR_PTR(-ENOMEM); @@ -2127,12 +2043,10 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev) goto err_wiphy_new; } - lbs_deb_leave(LBS_DEB_CFG80211); return wdev; err_wiphy_new: kfree(wdev); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ERR_PTR(ret); } @@ -2155,15 +2069,11 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv) }; size_t i; - lbs_deb_enter(LBS_DEB_CFG80211); - for (i = 0; i < ARRAY_SIZE(regmap); i++) if (regmap[i].code == priv->regioncode) { regulatory_hint(priv->wdev->wiphy, regmap[i].cn); break; } - - lbs_deb_leave(LBS_DEB_CFG80211); } static void lbs_reg_notifier(struct wiphy *wiphy, @@ -2171,15 +2081,9 @@ static void lbs_reg_notifier(struct wiphy *wiphy, { struct lbs_private *priv = wiphy_priv(wiphy); - lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " - "callback for domain %c%c\n", request->alpha2[0], - request->alpha2[1]); - memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); if (lbs_iface_active(priv)) lbs_set_11d_domain_info(priv); - - lbs_deb_leave(LBS_DEB_CFG80211); } /* @@ -2192,8 +2096,6 @@ int lbs_cfg_register(struct lbs_private *priv) struct wireless_dev *wdev = priv->wdev; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - wdev->wiphy->max_scan_ssids = 1; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; @@ -2229,13 +2131,11 @@ int lbs_cfg_register(struct lbs_private *priv) lbs_cfg_set_regulatory_hint(priv); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } void lbs_scan_deinit(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_CFG80211); cancel_delayed_work_sync(&priv->scan_work); } @@ -2244,8 +2144,6 @@ void lbs_cfg_free(struct lbs_private *priv) { struct wireless_dev *wdev = priv->wdev; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!wdev) return; diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c index 033ff881c751..c1f422918737 100644 --- a/drivers/net/wireless/marvell/libertas/cmd.c +++ b/drivers/net/wireless/marvell/libertas/cmd.c @@ -91,8 +91,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) int ret = -1; u32 i; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN); @@ -159,14 +157,12 @@ int lbs_update_hw_spec(struct lbs_private *priv) } out: - lbs_deb_leave(LBS_DEB_CMD); return ret; } static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy, struct cmd_header *resp) { - lbs_deb_enter(LBS_DEB_CMD); if (priv->is_host_sleep_activated) { priv->is_host_sleep_configured = 0; if (priv->psstate == PS_STATE_FULL_POWER) { @@ -176,7 +172,7 @@ static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy, } else { priv->is_host_sleep_configured = 1; } - lbs_deb_leave(LBS_DEB_CMD); + return 0; } @@ -236,8 +232,6 @@ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) struct cmd_ds_802_11_ps_mode cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(cmd_action); @@ -262,7 +256,6 @@ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd)); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -272,8 +265,6 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, struct cmd_ds_802_11_sleep_params cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - if (cmd_action == CMD_ACT_GET) { memset(&cmd, 0, sizeof(cmd)); } else { @@ -304,7 +295,6 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, sp->sp_reserved = le16_to_cpu(cmd.reserved); } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -312,8 +302,6 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv) { int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - if (priv->is_deep_sleep) { if (!wait_event_interruptible_timeout(priv->ds_awake_q, !priv->is_deep_sleep, (10 * HZ))) { @@ -322,7 +310,6 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv) } } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -330,8 +317,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) { int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - if (deep_sleep) { if (priv->is_deep_sleep != 1) { lbs_deb_cmd("deep sleep: sleep\n"); @@ -358,7 +343,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) } } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -366,10 +350,9 @@ static int lbs_ret_host_sleep_activate(struct lbs_private *priv, unsigned long dummy, struct cmd_header *cmd) { - lbs_deb_enter(LBS_DEB_FW); priv->is_host_sleep_activated = 1; wake_up_interruptible(&priv->host_sleep_q); - lbs_deb_leave(LBS_DEB_FW); + return 0; } @@ -379,8 +362,6 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) int ret = 0; uint32_t criteria = EHS_REMOVE_WAKEUP; - lbs_deb_enter(LBS_DEB_CMD); - if (host_sleep) { if (priv->is_host_sleep_activated != 1) { memset(&cmd, 0, sizeof(cmd)); @@ -438,8 +419,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) struct cmd_ds_802_11_snmp_mib cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof (cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); @@ -470,7 +449,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -488,8 +466,6 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) struct cmd_ds_802_11_snmp_mib cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof (cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_GET); @@ -513,7 +489,6 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) } out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -533,8 +508,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, struct cmd_ds_802_11_rf_tx_power cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_GET); @@ -548,7 +521,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, *maxlevel = cmd.maxlevel; } - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -565,8 +537,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) struct cmd_ds_802_11_rf_tx_power cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); @@ -576,7 +546,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -608,7 +577,6 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) ARPHRD_ETHER; } - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -624,8 +592,6 @@ static int lbs_get_channel(struct lbs_private *priv) struct cmd_ds_802_11_rf_channel cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET); @@ -638,7 +604,6 @@ static int lbs_get_channel(struct lbs_private *priv) lbs_deb_cmd("current radio channel is %d\n", ret); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -647,14 +612,12 @@ int lbs_update_channel(struct lbs_private *priv) int ret; /* the channel in f/w could be out of sync; get the current channel */ - lbs_deb_enter(LBS_DEB_ASSOC); - ret = lbs_get_channel(priv); if (ret > 0) { priv->channel = ret; ret = 0; } - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; } @@ -674,8 +637,6 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel) #endif int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET); @@ -690,7 +651,6 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel) priv->channel); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -708,8 +668,6 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) struct cmd_ds_802_11_rssi cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - BUG_ON(rssi == NULL); BUG_ON(nf == NULL); @@ -724,7 +682,6 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf)); } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -752,7 +709,6 @@ int lbs_set_11d_domain_info(struct lbs_private *priv) size_t triplet_size; int ret = 0; - lbs_deb_enter(LBS_DEB_11D); if (!priv->country_code[0]) goto out; @@ -849,7 +805,6 @@ int lbs_set_11d_domain_info(struct lbs_private *priv) ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd); out: - lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); return ret; } @@ -869,8 +824,6 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) struct cmd_ds_reg_access cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - BUG_ON(value == NULL); memset(&cmd, 0, sizeof(cmd)); @@ -894,7 +847,6 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) } out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -914,8 +866,6 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) struct cmd_ds_reg_access cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); @@ -933,7 +883,6 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) ret = lbs_cmd_with_response(priv, reg, &cmd); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -943,15 +892,13 @@ static void lbs_queue_cmd(struct lbs_private *priv, unsigned long flags; int addtail = 1; - lbs_deb_enter(LBS_DEB_HOST); - if (!cmdnode) { lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n"); - goto done; + return; } if (!cmdnode->cmdbuf->size) { lbs_deb_host("DNLD_CMD: cmd size is zero\n"); - goto done; + return; } cmdnode->result = 0; @@ -979,9 +926,6 @@ static void lbs_queue_cmd(struct lbs_private *priv, lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n", le16_to_cpu(cmdnode->cmdbuf->command)); - -done: - lbs_deb_leave(LBS_DEB_HOST); } static void lbs_submit_command(struct lbs_private *priv, @@ -994,8 +938,6 @@ static void lbs_submit_command(struct lbs_private *priv, int timeo = 3 * HZ; int ret; - lbs_deb_enter(LBS_DEB_HOST); - cmd = cmdnode->cmdbuf; spin_lock_irqsave(&priv->driver_lock, flags); @@ -1036,8 +978,6 @@ static void lbs_submit_command(struct lbs_private *priv, /* Setup the timer after transmit command */ mod_timer(&priv->command_timer, jiffies + timeo); } - - lbs_deb_leave(LBS_DEB_HOST); } /* @@ -1047,10 +987,8 @@ static void lbs_submit_command(struct lbs_private *priv, static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv, struct cmd_ctrl_node *cmdnode) { - lbs_deb_enter(LBS_DEB_HOST); - if (!cmdnode) - goto out; + return; cmdnode->callback = NULL; cmdnode->callback_arg = 0; @@ -1058,8 +996,6 @@ static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv, memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE); list_add_tail(&cmdnode->list, &priv->cmdfreeq); - out: - lbs_deb_leave(LBS_DEB_HOST); } static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv, @@ -1107,8 +1043,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) struct cmd_ds_802_11_radio_control cmd; int ret = -EINVAL; - lbs_deb_enter(LBS_DEB_CMD); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); cmd.control = 0; @@ -1141,7 +1075,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -1149,15 +1082,11 @@ void lbs_set_mac_control(struct lbs_private *priv) { struct cmd_ds_mac_control cmd; - lbs_deb_enter(LBS_DEB_CMD); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(priv->mac_control); cmd.reserved = 0; lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd)); - - lbs_deb_leave(LBS_DEB_CMD); } int lbs_set_mac_control_sync(struct lbs_private *priv) @@ -1165,14 +1094,11 @@ int lbs_set_mac_control_sync(struct lbs_private *priv) struct cmd_ds_mac_control cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(priv->mac_control); cmd.reserved = 0; ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -1191,8 +1117,6 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) u32 i; struct cmd_ctrl_node *cmdarray; - lbs_deb_enter(LBS_DEB_HOST); - /* Allocate and initialize the command array */ bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS; if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) { @@ -1219,7 +1143,6 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -1235,8 +1158,6 @@ int lbs_free_cmd_buffer(struct lbs_private *priv) struct cmd_ctrl_node *cmdarray; unsigned int i; - lbs_deb_enter(LBS_DEB_HOST); - /* need to check if cmd array is allocated or not */ if (priv->cmd_array == NULL) { lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n"); @@ -1260,7 +1181,6 @@ int lbs_free_cmd_buffer(struct lbs_private *priv) } done: - lbs_deb_leave(LBS_DEB_HOST); return 0; } @@ -1278,8 +1198,6 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) struct cmd_ctrl_node *tempnode; unsigned long flags; - lbs_deb_enter(LBS_DEB_HOST); - if (!priv) return NULL; @@ -1296,7 +1214,6 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_HOST); return tempnode; } @@ -1318,8 +1235,6 @@ int lbs_execute_next_command(struct lbs_private *priv) /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the * only caller to us is lbs_thread() and we get even when a * data packet is received */ - lbs_deb_enter(LBS_DEB_THREAD); - spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd) { @@ -1440,7 +1355,6 @@ int lbs_execute_next_command(struct lbs_private *priv) ret = 0; done: - lbs_deb_leave(LBS_DEB_THREAD); return ret; } @@ -1449,7 +1363,6 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) unsigned long flags; int ret; - lbs_deb_enter(LBS_DEB_HOST); lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep, sizeof(confirm_sleep)); @@ -1457,7 +1370,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) sizeof(confirm_sleep)); if (ret) { netdev_alert(priv->dev, "confirm_sleep failed\n"); - goto out; + return; } spin_lock_irqsave(&priv->driver_lock, flags); @@ -1475,9 +1388,6 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) priv->psstate = PS_STATE_SLEEP; spin_unlock_irqrestore(&priv->driver_lock, flags); - -out: - lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1493,8 +1403,6 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) unsigned long flags =0; int allowed = 1; - lbs_deb_enter(LBS_DEB_HOST); - spin_lock_irqsave(&priv->driver_lock, flags); if (priv->dnld_sent) { allowed = 0; @@ -1520,8 +1428,6 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) } else { lbs_deb_host("sleep confirm has been delayed\n"); } - - lbs_deb_leave(LBS_DEB_HOST); } @@ -1596,8 +1502,6 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, { struct cmd_ctrl_node *cmdnode; - lbs_deb_enter(LBS_DEB_HOST); - if (priv->surpriseremoved) { lbs_deb_host("PREP_CMD: card removed\n"); cmdnode = ERR_PTR(-ENOENT); @@ -1643,17 +1547,14 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, wake_up(&priv->waitq); done: - lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode); return cmdnode; } void lbs_cmd_async(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size) { - lbs_deb_enter(LBS_DEB_CMD); __lbs_cmd_async(priv, command, in_cmd, in_cmd_size, lbs_cmd_async_callback, 0); - lbs_deb_leave(LBS_DEB_CMD); } int __lbs_cmd(struct lbs_private *priv, uint16_t command, @@ -1665,8 +1566,6 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, unsigned long flags; int ret = 0; - lbs_deb_enter(LBS_DEB_HOST); - cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size, callback, callback_arg); if (IS_ERR(cmdnode)) { @@ -1693,7 +1592,6 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, spin_unlock_irqrestore(&priv->driver_lock, flags); done: - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(__lbs_cmd); diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c index c753e36c2c0e..aaf01619de59 100644 --- a/drivers/net/wireless/marvell/libertas/cmdresp.c +++ b/drivers/net/wireless/marvell/libertas/cmdresp.c @@ -32,8 +32,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv, if (priv->connect_status != LBS_CONNECTED) return; - lbs_deb_enter(LBS_DEB_ASSOC); - /* * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. * It causes problem in the Supplicant @@ -61,7 +59,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv, lbs_deb_cmd("disconnected, so exit PS mode\n"); lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false); } - lbs_deb_leave(LBS_DEB_ASSOC); } int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) @@ -72,8 +69,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) unsigned long flags; uint16_t result; - lbs_deb_enter(LBS_DEB_HOST); - mutex_lock(&priv->lock); spin_lock_irqsave(&priv->driver_lock, flags); @@ -221,7 +216,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) done: mutex_unlock(&priv->lock); - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -230,8 +224,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event) int ret = 0; struct cmd_header cmd; - lbs_deb_enter(LBS_DEB_CMD); - switch (event) { case MACREG_INT_CODE_LINK_SENSED: lbs_deb_cmd("EVENT: link sensed\n"); @@ -359,6 +351,5 @@ int lbs_process_event(struct lbs_private *priv, u32 event) break; } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/marvell/libertas/defs.h b/drivers/net/wireless/marvell/libertas/defs.h index 407784aca627..d3221444e51c 100644 --- a/drivers/net/wireless/marvell/libertas/defs.h +++ b/drivers/net/wireless/marvell/libertas/defs.h @@ -55,15 +55,6 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0) #endif -#define lbs_deb_enter(grp) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__); -#define lbs_deb_enter_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args); -#define lbs_deb_leave(grp) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__); -#define lbs_deb_leave_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \ - __func__, ##args); #define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args) #define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args) #define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args) diff --git a/drivers/net/wireless/marvell/libertas/ethtool.c b/drivers/net/wireless/marvell/libertas/ethtool.c index f955b2d66ed6..693868f16921 100644 --- a/drivers/net/wireless/marvell/libertas/ethtool.c +++ b/drivers/net/wireless/marvell/libertas/ethtool.c @@ -41,8 +41,6 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, struct cmd_ds_802_11_eeprom_access cmd; int ret; - lbs_deb_enter(LBS_DEB_ETHTOOL); - if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN || eeprom->len > LBS_EEPROM_READ_LEN) { ret = -EINVAL; @@ -59,7 +57,6 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, memcpy(bytes, cmd.value, eeprom->len); out: - lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c index f499efc6abcf..7d88223f890b 100644 --- a/drivers/net/wireless/marvell/libertas/if_cs.c +++ b/drivers/net/wireless/marvell/libertas/if_cs.c @@ -336,13 +336,11 @@ static inline u32 get_model(u16 manf_id, u16 card_id) static inline void if_cs_enable_ints(struct if_cs_card *card) { - lbs_deb_enter(LBS_DEB_CS); if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); } static inline void if_cs_disable_ints(struct if_cs_card *card) { - lbs_deb_enter(LBS_DEB_CS); if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); } @@ -355,7 +353,6 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) int ret = -1; int loops = 0; - lbs_deb_enter(LBS_DEB_CS); if_cs_disable_ints(card); /* Is hardware ready? */ @@ -388,7 +385,6 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) done: if_cs_enable_ints(card); - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -400,7 +396,6 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) struct if_cs_card *card = (struct if_cs_card *)priv->card; u16 status; - lbs_deb_enter(LBS_DEB_CS); if_cs_disable_ints(card); status = if_cs_read16(card, IF_CS_CARD_STATUS); @@ -416,8 +411,6 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); if_cs_enable_ints(card); - - lbs_deb_leave(LBS_DEB_CS); } /* @@ -429,8 +422,6 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) int ret = -1; u16 status; - lbs_deb_enter(LBS_DEB_CS); - /* is hardware ready? */ status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); if ((status & IF_CS_BIT_RESP) == 0) { @@ -463,7 +454,6 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) spin_unlock_irqrestore(&priv->driver_lock, flags); out: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len); return ret; } @@ -473,8 +463,6 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) u16 len; u8 *data; - lbs_deb_enter(LBS_DEB_CS); - len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { netdev_err(priv->dev, @@ -501,7 +489,6 @@ dat_err: if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); out: - lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); return skb; } @@ -511,8 +498,6 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) struct lbs_private *priv = card->priv; u16 cause; - lbs_deb_enter(LBS_DEB_CS); - /* Ask card interrupt cause register if there is something for us */ cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); lbs_deb_cs("cause 0x%04x\n", cause); @@ -569,7 +554,6 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) /* Clear interrupt cause */ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); - lbs_deb_leave(LBS_DEB_CS); return IRQ_HANDLED; } @@ -591,8 +575,6 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) int sent = 0; u8 scratch; - lbs_deb_enter(LBS_DEB_CS); - /* * This is the only place where an unaligned register access happens on * the CF8305 card, therefore for the sake of speed of the driver, we do @@ -671,7 +653,6 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) } done: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -683,8 +664,6 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) int len = 0; int sent; - lbs_deb_enter(LBS_DEB_CS); - lbs_deb_cs("fw size %td\n", fw->size); ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, @@ -734,7 +713,6 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) pr_err("firmware download failed\n"); done: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -792,8 +770,6 @@ static int if_cs_host_to_card(struct lbs_private *priv, { int ret = -1; - lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb); - switch (type) { case MVMS_DAT: priv->dnld_sent = DNLD_DATA_SENT; @@ -809,7 +785,6 @@ static int if_cs_host_to_card(struct lbs_private *priv, __func__, type); } - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -818,14 +793,10 @@ static void if_cs_release(struct pcmcia_device *p_dev) { struct if_cs_card *card = p_dev->priv; - lbs_deb_enter(LBS_DEB_CS); - free_irq(p_dev->irq, card); pcmcia_disable_device(p_dev); if (card->iobase) ioport_unmap(card->iobase); - - lbs_deb_leave(LBS_DEB_CS); } @@ -850,8 +821,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) struct lbs_private *priv; struct if_cs_card *card; - lbs_deb_enter(LBS_DEB_CS); - card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); if (!card) goto out; @@ -961,7 +930,6 @@ out2: out1: pcmcia_disable_device(p_dev); out: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -970,15 +938,11 @@ static void if_cs_detach(struct pcmcia_device *p_dev) { struct if_cs_card *card = p_dev->priv; - lbs_deb_enter(LBS_DEB_CS); - lbs_stop_card(card->priv); lbs_remove_card(card->priv); if_cs_disable_ints(card); if_cs_release(p_dev); kfree(card); - - lbs_deb_leave(LBS_DEB_CS); } diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 47f4a14c84fe..2300e796c6ab 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -211,8 +211,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card, unsigned long flags; u8 i; - lbs_deb_enter(LBS_DEB_SDIO); - if (size > LBS_CMD_BUFFER_SIZE) { lbs_deb_sdio("response packet too large (%d bytes)\n", (int)size); @@ -233,7 +231,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card, ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -242,9 +239,6 @@ static int if_sdio_handle_data(struct if_sdio_card *card, { int ret; struct sk_buff *skb; - char *data; - - lbs_deb_enter(LBS_DEB_SDIO); if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_deb_sdio("response packet too large (%d bytes)\n", @@ -261,17 +255,13 @@ static int if_sdio_handle_data(struct if_sdio_card *card, skb_reserve(skb, NET_IP_ALIGN); - data = skb_put(skb, size); - - memcpy(data, buffer, size); + skb_put_data(skb, buffer, size); lbs_process_rxed_packet(card->priv, skb); ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -281,8 +271,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card, int ret; u32 event; - lbs_deb_enter(LBS_DEB_SDIO); - if (card->model == MODEL_8385) { event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); if (ret) @@ -307,8 +295,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card, ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -337,8 +323,6 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) int ret; u16 size, type, chunk; - lbs_deb_enter(LBS_DEB_SDIO); - size = if_sdio_read_rx_len(card, &ret); if (ret) goto out; @@ -410,8 +394,6 @@ out: if (ret) pr_err("problem fetching packet from firmware\n"); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -422,8 +404,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) int ret; unsigned long flags; - lbs_deb_enter(LBS_DEB_SDIO); - card = container_of(work, struct if_sdio_card, packet_worker); while (1) { @@ -451,8 +431,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) kfree(packet); } - - lbs_deb_leave(LBS_DEB_SDIO); } /********************************************************************/ @@ -471,8 +449,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card, const u8 *firmware; size_t size; - lbs_deb_enter(LBS_DEB_SDIO); - chunk_buffer = kzalloc(64, GFP_KERNEL); if (!chunk_buffer) { ret = -ENOMEM; @@ -556,7 +532,6 @@ out: if (ret) pr_err("failed to load helper firmware\n"); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -570,8 +545,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card, const u8 *firmware; size_t size, req_size; - lbs_deb_enter(LBS_DEB_SDIO); - chunk_buffer = kzalloc(512, GFP_KERNEL); if (!chunk_buffer) { ret = -ENOMEM; @@ -691,7 +664,6 @@ out: if (ret) pr_err("failed to load firmware\n"); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -725,8 +697,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) int ret; u16 scratch; - lbs_deb_enter(LBS_DEB_SDIO); - /* * Disable interrupts */ @@ -769,7 +739,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) fw_table, if_sdio_do_prog_firmware); out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -948,8 +917,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv, u16 size; unsigned long flags; - lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb); - card = priv->card; if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) { @@ -1013,8 +980,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv, ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -1040,7 +1005,6 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv) struct if_sdio_card *card = priv->card; int ret = -1; - lbs_deb_enter(LBS_DEB_SDIO); sdio_claim_host(card->func); sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret); @@ -1048,7 +1012,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv) netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); + return ret; } @@ -1057,7 +1021,6 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) struct if_sdio_card *card = priv->card; int ret = -1; - lbs_deb_enter(LBS_DEB_SDIO); sdio_claim_host(card->func); sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret); @@ -1065,7 +1028,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); + return ret; } @@ -1143,19 +1106,17 @@ static void if_sdio_interrupt(struct sdio_func *func) struct if_sdio_card *card; u8 cause; - lbs_deb_enter(LBS_DEB_SDIO); - card = sdio_get_drvdata(func); cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret); if (ret || !cause) - goto out; + return; lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause); sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret); if (ret) - goto out; + return; /* * Ignore the define name, this really means the card has @@ -1169,13 +1130,8 @@ static void if_sdio_interrupt(struct sdio_func *func) if (cause & IF_SDIO_H_INT_UPLD) { ret = if_sdio_card_to_host(card); if (ret) - goto out; + return; } - - ret = 0; - -out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); } static int if_sdio_probe(struct sdio_func *func, @@ -1187,8 +1143,6 @@ static int if_sdio_probe(struct sdio_func *func, unsigned int model; struct if_sdio_packet *packet; - lbs_deb_enter(LBS_DEB_SDIO); - for (i = 0;i < func->card->num_info;i++) { if (sscanf(func->card->info[i], "802.11 SDIO ID: %x", &model) == 1) @@ -1273,8 +1227,6 @@ static int if_sdio_probe(struct sdio_func *func, goto err_activate_card; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; err_activate_card: @@ -1298,8 +1250,6 @@ static void if_sdio_remove(struct sdio_func *func) struct if_sdio_card *card; struct if_sdio_packet *packet; - lbs_deb_enter(LBS_DEB_SDIO); - card = sdio_get_drvdata(func); /* Undo decrement done above in if_sdio_probe */ @@ -1335,7 +1285,6 @@ static void if_sdio_remove(struct sdio_func *func) } kfree(card); - lbs_deb_leave(LBS_DEB_SDIO); } static int if_sdio_suspend(struct device *dev) @@ -1415,8 +1364,6 @@ static int __init if_sdio_init_module(void) { int ret = 0; - lbs_deb_enter(LBS_DEB_SDIO); - printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n"); printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n"); @@ -1425,23 +1372,17 @@ static int __init if_sdio_init_module(void) /* Clear the flag in case user removes the card. */ user_rmmod = 0; - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } static void __exit if_sdio_exit_module(void) { - lbs_deb_enter(LBS_DEB_SDIO); - /* Set the flag as user is removing this module. */ user_rmmod = 1; cancel_work_sync(&card_reset_work); sdio_unregister_driver(&if_sdio_driver); - - lbs_deb_leave(LBS_DEB_SDIO); } module_init(if_sdio_init_module); diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index 7b4955cc38db..e9aec6cb1105 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -466,8 +466,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, const u8 *fw; u8 temp[HELPER_FW_LOAD_CHUNK_SZ]; - lbs_deb_enter(LBS_DEB_SPI); - err = spu_set_interrupt_mode(card, 1, 0); if (err) goto out; @@ -533,7 +531,7 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, out: if (err) pr_err("failed to load helper firmware (err=%d)\n", err); - lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); + return err; } @@ -588,8 +586,6 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, const u8 *fw; u16 num_crc_errs; - lbs_deb_enter(LBS_DEB_SPI); - err = spu_set_interrupt_mode(card, 1, 0); if (err) goto out; @@ -666,7 +662,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, out: if (err) pr_err("failed to load firmware (err=%d)\n", err); - lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); + return err; } @@ -699,8 +695,6 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0); - lbs_deb_enter(LBS_DEB_SPI); - /* How many bytes are there to read? */ err = spu_read_u16(card, IF_SPI_SCRATCH_2_REG, &len); if (err) @@ -735,7 +729,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) out: if (err) netdev_err(priv->dev, "%s: err=%d\n", __func__, err); - lbs_deb_leave(LBS_DEB_SPI); + return err; } @@ -748,8 +742,6 @@ static int if_spi_c2h_data(struct if_spi_card *card) u16 len; int err = 0; - lbs_deb_enter(LBS_DEB_SPI); - /* How many bytes are there to read? */ err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len); if (err) @@ -794,7 +786,7 @@ free_skb: out: if (err) netdev_err(priv->dev, "%s: err=%d\n", __func__, err); - lbs_deb_leave(LBS_DEB_SPI); + return err; } @@ -870,8 +862,6 @@ static void if_spi_host_to_card_worker(struct work_struct *work) card = container_of(work, struct if_spi_card, packet_work); priv = card->priv; - lbs_deb_enter(LBS_DEB_SPI); - /* * Read the host interrupt status register to see what we * can do. @@ -943,8 +933,6 @@ static void if_spi_host_to_card_worker(struct work_struct *work) err: if (err) netdev_err(priv->dev, "%s: got error %d\n", __func__, err); - - lbs_deb_leave(LBS_DEB_SPI); } /* @@ -962,8 +950,6 @@ static int if_spi_host_to_card(struct lbs_private *priv, struct if_spi_packet *packet; u16 blen; - lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); - if (nb == 0) { netdev_err(priv->dev, "%s: invalid size requested: %d\n", __func__, nb); @@ -1004,7 +990,6 @@ static int if_spi_host_to_card(struct lbs_private *priv, /* Queue spi xfer work */ queue_work(card->workqueue, &card->packet_work); out: - lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err); return err; } @@ -1035,8 +1020,6 @@ static int if_spi_init_card(struct if_spi_card *card) const struct firmware *helper = NULL; const struct firmware *mainfw = NULL; - lbs_deb_enter(LBS_DEB_SPI); - err = spu_init(card, card->pdata->use_dummy_writes); if (err) goto out; @@ -1093,7 +1076,6 @@ static int if_spi_init_card(struct if_spi_card *card) goto out; out: - lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); return err; } @@ -1126,8 +1108,6 @@ static int if_spi_probe(struct spi_device *spi) struct libertas_spi_platform_data *pdata = dev_get_platdata(&spi->dev); int err = 0; - lbs_deb_enter(LBS_DEB_SPI); - if (!pdata) { err = -EINVAL; goto out; @@ -1221,7 +1201,6 @@ teardown: if (pdata->teardown) pdata->teardown(spi); out: - lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); return err; } @@ -1231,7 +1210,6 @@ static int libertas_spi_remove(struct spi_device *spi) struct lbs_private *priv = card->priv; lbs_deb_spi("libertas_spi_remove\n"); - lbs_deb_enter(LBS_DEB_SPI); cancel_work_sync(&card->resume_work); @@ -1243,7 +1221,7 @@ static int libertas_spi_remove(struct spi_device *spi) if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); - lbs_deb_leave(LBS_DEB_SPI); + return 0; } @@ -1297,18 +1275,16 @@ static struct spi_driver libertas_spi_driver = { static int __init if_spi_init_module(void) { int ret = 0; - lbs_deb_enter(LBS_DEB_SPI); + printk(KERN_INFO "libertas_spi: Libertas SPI driver\n"); ret = spi_register_driver(&libertas_spi_driver); - lbs_deb_leave(LBS_DEB_SPI); + return ret; } static void __exit if_spi_exit_module(void) { - lbs_deb_enter(LBS_DEB_SPI); spi_unregister_driver(&libertas_spi_driver); - lbs_deb_leave(LBS_DEB_SPI); } module_init(if_spi_init_module); diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index aba0c9995b14..e53025ea6689 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -111,8 +111,6 @@ static void if_usb_write_bulk_callback(struct urb *urb) */ static void if_usb_free(struct if_usb_card *cardp) { - lbs_deb_enter(LBS_DEB_USB); - /* Unlink tx & rx urb */ usb_kill_urb(cardp->tx_urb); usb_kill_urb(cardp->rx_urb); @@ -125,8 +123,6 @@ static void if_usb_free(struct if_usb_card *cardp) kfree(cardp->ep_out_buf); cardp->ep_out_buf = NULL; - - lbs_deb_leave(LBS_DEB_USB); } static void if_usb_setup_firmware(struct lbs_private *priv) @@ -306,8 +302,6 @@ static void if_usb_disconnect(struct usb_interface *intf) struct if_usb_card *cardp = usb_get_intfdata(intf); struct lbs_private *priv = cardp->priv; - lbs_deb_enter(LBS_DEB_MAIN); - cardp->surprise_removed = 1; if (priv) { @@ -320,8 +314,6 @@ static void if_usb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); - - lbs_deb_leave(LBS_DEB_MAIN); } /** @@ -388,8 +380,6 @@ static int if_usb_reset_device(struct if_usb_card *cardp) struct cmd_header *cmd = cardp->ep_out_buf + 4; int ret; - lbs_deb_enter(LBS_DEB_USB); - *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); cmd->command = cpu_to_le16(CMD_802_11_RESET); @@ -407,8 +397,6 @@ static int if_usb_reset_device(struct if_usb_card *cardp) if_usb_reset_olpc_card(NULL); #endif - lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); - return ret; } @@ -671,8 +659,6 @@ static void if_usb_receive(struct urb *urb) __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET); uint32_t event; - lbs_deb_enter(LBS_DEB_USB); - if (recvlength) { if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n", @@ -688,7 +674,7 @@ static void if_usb_receive(struct urb *urb) recvlength, recvtype); } else if (urb->status) { kfree_skb(skb); - goto rx_exit; + return; } switch (recvtype) { @@ -724,8 +710,6 @@ static void if_usb_receive(struct urb *urb) setup_for_next: if_usb_submit_rx_urb(cardp); -rx_exit: - lbs_deb_leave(LBS_DEB_USB); } /** @@ -835,8 +819,6 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, int i = 0; static int reset_count = 10; - lbs_deb_enter(LBS_DEB_USB); - if (ret) { pr_err("failed to find firmware (%d)\n", ret); goto done; @@ -942,7 +924,6 @@ restart: done: cardp->fw = NULL; - lbs_deb_leave(LBS_DEB_USB); } @@ -953,8 +934,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) struct lbs_private *priv = cardp->priv; int ret; - lbs_deb_enter(LBS_DEB_USB); - if (priv->psstate != PS_STATE_FULL_POWER) { ret = -1; goto out; @@ -978,7 +957,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) usb_kill_urb(cardp->rx_urb); out: - lbs_deb_leave(LBS_DEB_USB); return ret; } @@ -987,13 +965,10 @@ static int if_usb_resume(struct usb_interface *intf) struct if_usb_card *cardp = usb_get_intfdata(intf); struct lbs_private *priv = cardp->priv; - lbs_deb_enter(LBS_DEB_USB); - if_usb_submit_rx_urb(cardp); lbs_resume(priv); - lbs_deb_leave(LBS_DEB_USB); return 0; } #else diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index dde065d0d5c1..aefa88f4f29c 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -180,7 +180,6 @@ static int lbs_dev_open(struct net_device *dev) struct lbs_private *priv = dev->ml_priv; int ret = 0; - lbs_deb_enter(LBS_DEB_NET); if (!priv->iface_running) { ret = lbs_start_iface(priv); if (ret) @@ -197,7 +196,6 @@ static int lbs_dev_open(struct net_device *dev) spin_unlock_irq(&priv->driver_lock); out: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } @@ -216,8 +214,6 @@ int lbs_stop_iface(struct lbs_private *priv) unsigned long flags; int ret = 0; - lbs_deb_enter(LBS_DEB_MAIN); - spin_lock_irqsave(&priv->driver_lock, flags); priv->iface_running = false; kfree_skb(priv->currenttxskb); @@ -236,7 +232,6 @@ int lbs_stop_iface(struct lbs_private *priv) if (priv->power_save) ret = priv->power_save(priv); - lbs_deb_leave(LBS_DEB_MAIN); return ret; } @@ -250,8 +245,6 @@ static int lbs_eth_stop(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; - lbs_deb_enter(LBS_DEB_NET); - if (priv->connect_status == LBS_CONNECTED) lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING); @@ -269,7 +262,6 @@ static int lbs_eth_stop(struct net_device *dev) if (!lbs_iface_active(priv)) lbs_stop_iface(priv); - lbs_deb_leave(LBS_DEB_NET); return 0; } @@ -277,8 +269,6 @@ void lbs_host_to_card_done(struct lbs_private *priv) { unsigned long flags; - lbs_deb_enter(LBS_DEB_THREAD); - spin_lock_irqsave(&priv->driver_lock, flags); del_timer(&priv->tx_lockup_timer); @@ -291,7 +281,6 @@ void lbs_host_to_card_done(struct lbs_private *priv) } spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_THREAD); } EXPORT_SYMBOL_GPL(lbs_host_to_card_done); @@ -301,8 +290,6 @@ int lbs_set_mac_address(struct net_device *dev, void *addr) struct lbs_private *priv = dev->ml_priv; struct sockaddr *phwaddr = addr; - lbs_deb_enter(LBS_DEB_NET); - /* * Can only set MAC address when all interfaces are down, to be written * to the hardware when one of them is brought up. @@ -318,7 +305,6 @@ int lbs_set_mac_address(struct net_device *dev, void *addr) if (priv->mesh_dev) memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } @@ -378,8 +364,6 @@ void lbs_update_mcast(struct lbs_private *priv) int nr_addrs; int old_mac_control = priv->mac_control; - lbs_deb_enter(LBS_DEB_NET); - if (netif_running(priv->dev)) dev_flags |= priv->dev->flags; if (priv->mesh_dev && netif_running(priv->mesh_dev)) @@ -424,8 +408,6 @@ void lbs_update_mcast(struct lbs_private *priv) out_set_mac_control: if (priv->mac_control != old_mac_control) lbs_set_mac_control(priv); - - lbs_deb_leave(LBS_DEB_NET); } static void lbs_set_mcast_worker(struct work_struct *work) @@ -455,8 +437,6 @@ static int lbs_thread(void *data) struct lbs_private *priv = dev->ml_priv; wait_queue_entry_t wait; - lbs_deb_enter(LBS_DEB_THREAD); - init_waitqueue_entry(&wait, current); for (;;) { @@ -648,7 +628,6 @@ static int lbs_thread(void *data) del_timer(&priv->tx_lockup_timer); del_timer(&priv->auto_deepsleep_timer); - lbs_deb_leave(LBS_DEB_THREAD); return 0; } @@ -664,8 +643,6 @@ static int lbs_setup_firmware(struct lbs_private *priv) int ret = -1; s16 curlevel = 0, minlevel = 0, maxlevel = 0; - lbs_deb_enter(LBS_DEB_FW); - /* Read MAC address from firmware */ eth_broadcast_addr(priv->current_addr); ret = lbs_update_hw_spec(priv); @@ -687,7 +664,6 @@ static int lbs_setup_firmware(struct lbs_private *priv) ret = lbs_set_mac_control_sync(priv); done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; } @@ -695,8 +671,6 @@ int lbs_suspend(struct lbs_private *priv) { int ret; - lbs_deb_enter(LBS_DEB_FW); - if (priv->is_deep_sleep) { ret = lbs_set_deep_sleep(priv, 0); if (ret) { @@ -713,7 +687,6 @@ int lbs_suspend(struct lbs_private *priv) if (priv->mesh_dev) netif_device_detach(priv->mesh_dev); - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_suspend); @@ -722,8 +695,6 @@ int lbs_resume(struct lbs_private *priv) { int ret; - lbs_deb_enter(LBS_DEB_FW); - ret = lbs_set_host_sleep(priv, 0); netif_device_attach(priv->dev); @@ -741,7 +712,6 @@ int lbs_resume(struct lbs_private *priv) if (priv->setup_fw_on_resume) ret = lbs_setup_firmware(priv); - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_resume); @@ -757,7 +727,6 @@ static void lbs_cmd_timeout_handler(unsigned long data) struct lbs_private *priv = (struct lbs_private *)data; unsigned long flags; - lbs_deb_enter(LBS_DEB_CMD); spin_lock_irqsave(&priv->driver_lock, flags); if (!priv->cur_cmd) @@ -778,7 +747,6 @@ static void lbs_cmd_timeout_handler(unsigned long data) wake_up(&priv->waitq); out: spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_CMD); } /** @@ -793,7 +761,6 @@ static void lbs_tx_lockup_handler(unsigned long data) struct lbs_private *priv = (struct lbs_private *)data; unsigned long flags; - lbs_deb_enter(LBS_DEB_TX); spin_lock_irqsave(&priv->driver_lock, flags); netdev_info(priv->dev, "TX lockup detected\n"); @@ -804,7 +771,6 @@ static void lbs_tx_lockup_handler(unsigned long data) wake_up_interruptible(&priv->waitq); spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_TX); } /** @@ -817,8 +783,6 @@ static void auto_deepsleep_timer_fn(unsigned long data) { struct lbs_private *priv = (struct lbs_private *)data; - lbs_deb_enter(LBS_DEB_CMD); - if (priv->is_activity_detected) { priv->is_activity_detected = 0; } else { @@ -836,32 +800,25 @@ static void auto_deepsleep_timer_fn(unsigned long data) } mod_timer(&priv->auto_deepsleep_timer , jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000); - lbs_deb_leave(LBS_DEB_CMD); } int lbs_enter_auto_deep_sleep(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_SDIO); - priv->is_auto_deep_sleep_enabled = 1; if (priv->is_deep_sleep) priv->wakeup_dev_required = 1; mod_timer(&priv->auto_deepsleep_timer , jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000); - lbs_deb_leave(LBS_DEB_SDIO); return 0; } int lbs_exit_auto_deep_sleep(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_SDIO); - priv->is_auto_deep_sleep_enabled = 0; priv->auto_deep_sleep_timeout = 0; del_timer(&priv->auto_deepsleep_timer); - lbs_deb_leave(LBS_DEB_SDIO); return 0; } @@ -869,8 +826,6 @@ static int lbs_init_adapter(struct lbs_private *priv) { int ret; - lbs_deb_enter(LBS_DEB_MAIN); - eth_broadcast_addr(priv->current_addr); priv->connect_status = LBS_DISCONNECTED; @@ -921,22 +876,16 @@ static int lbs_init_adapter(struct lbs_private *priv) } out: - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); - return ret; } static void lbs_free_adapter(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_MAIN); - lbs_free_cmd_buffer(priv); kfifo_free(&priv->event_fifo); del_timer(&priv->command_timer); del_timer(&priv->tx_lockup_timer); del_timer(&priv->auto_deepsleep_timer); - - lbs_deb_leave(LBS_DEB_MAIN); } static const struct net_device_ops lbs_netdev_ops = { @@ -962,8 +911,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) struct wireless_dev *wdev; struct lbs_private *priv = NULL; - lbs_deb_enter(LBS_DEB_MAIN); - /* Allocate an Ethernet device and register it */ wdev = lbs_cfg_alloc(dmdev); if (IS_ERR(wdev)) { @@ -1031,7 +978,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv = NULL; done: - lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv); return priv; } EXPORT_SYMBOL_GPL(lbs_add_card); @@ -1041,8 +987,6 @@ void lbs_remove_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; - lbs_deb_enter(LBS_DEB_MAIN); - lbs_remove_mesh(priv); if (priv->wiphy_registered) @@ -1083,8 +1027,6 @@ void lbs_remove_card(struct lbs_private *priv) lbs_free_adapter(priv); lbs_cfg_free(priv); free_netdev(dev); - - lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(lbs_remove_card); @@ -1105,8 +1047,6 @@ int lbs_start_card(struct lbs_private *priv) struct net_device *dev = priv->dev; int ret = -1; - lbs_deb_enter(LBS_DEB_MAIN); - /* poke the firmware */ ret = lbs_setup_firmware(priv); if (ret) @@ -1133,7 +1073,6 @@ int lbs_start_card(struct lbs_private *priv) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_start_card); @@ -1143,16 +1082,14 @@ void lbs_stop_card(struct lbs_private *priv) { struct net_device *dev; - lbs_deb_enter(LBS_DEB_MAIN); - if (!priv) - goto out; + return; dev = priv->dev; /* If the netdev isn't registered, it means that lbs_start_card() was * never called so we have nothing to do here. */ if (dev->reg_state != NETREG_REGISTERED) - goto out; + return; netif_stop_queue(dev); netif_carrier_off(dev); @@ -1160,9 +1097,6 @@ void lbs_stop_card(struct lbs_private *priv) lbs_debugfs_remove_one(priv); lbs_deinit_mesh(priv); unregister_netdev(dev); - -out: - lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(lbs_stop_card); @@ -1171,7 +1105,6 @@ void lbs_queue_event(struct lbs_private *priv, u32 event) { unsigned long flags; - lbs_deb_enter(LBS_DEB_THREAD); spin_lock_irqsave(&priv->driver_lock, flags); if (priv->psstate == PS_STATE_SLEEP) @@ -1182,14 +1115,11 @@ void lbs_queue_event(struct lbs_private *priv, u32 event) wake_up(&priv->waitq); spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_THREAD); } EXPORT_SYMBOL_GPL(lbs_queue_event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) { - lbs_deb_enter(LBS_DEB_THREAD); - if (priv->psstate == PS_STATE_SLEEP) priv->psstate = PS_STATE_AWAKE; @@ -1198,28 +1128,23 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) priv->resp_idx = resp_idx; wake_up(&priv->waitq); - - lbs_deb_leave(LBS_DEB_THREAD); } EXPORT_SYMBOL_GPL(lbs_notify_command_response); static int __init lbs_init_module(void) { - lbs_deb_enter(LBS_DEB_MAIN); memset(&confirm_sleep, 0, sizeof(confirm_sleep)); confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE); confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep)); confirm_sleep.action = cpu_to_le16(PS_MODE_ACTION_SLEEP_CONFIRMED); lbs_debugfs_init(); - lbs_deb_leave(LBS_DEB_MAIN); + return 0; } static void __exit lbs_exit_module(void) { - lbs_deb_enter(LBS_DEB_MAIN); lbs_debugfs_remove(); - lbs_deb_leave(LBS_DEB_MAIN); } module_init(lbs_init_module); diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index d0c881dd5846..37ace5cb309d 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -26,8 +26,6 @@ static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, { int ret; - lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); - cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS); cmd->hdr.size = cpu_to_le16(sizeof(*cmd)); cmd->hdr.result = 0; @@ -36,7 +34,6 @@ static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -47,8 +44,6 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, int ret; u16 command = CMD_MESH_CONFIG_OLD; - lbs_deb_enter(LBS_DEB_CMD); - /* * Command id is 0xac for v10 FW along with mesh interface * id in bits 14-13-12. @@ -66,7 +61,6 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, command, cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -239,8 +233,9 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, memset(&mesh_access, 0, sizeof(mesh_access)); mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); - if (!kstrtoul(buf, 10, &retry_limit)) - return -ENOTSUPP; + ret = kstrtoul(buf, 10, &retry_limit); + if (ret) + return ret; if (retry_limit > 15) return -ENOTSUPP; @@ -823,8 +818,6 @@ int lbs_init_mesh(struct lbs_private *priv) { int ret = 0; - lbs_deb_enter(LBS_DEB_MESH); - /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ /* 5.110.22 have mesh command with 0xa3 command id */ @@ -870,7 +863,6 @@ int lbs_init_mesh(struct lbs_private *priv) ret = 1; } - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } @@ -887,14 +879,11 @@ int lbs_deinit_mesh(struct lbs_private *priv) struct net_device *dev = priv->dev; int ret = 0; - lbs_deb_enter(LBS_DEB_MESH); - if (priv->mesh_tlv) { device_remove_file(&dev->dev, &dev_attr_lbs_mesh); ret = 1; } - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } @@ -909,7 +898,6 @@ static int lbs_mesh_stop(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; - lbs_deb_enter(LBS_DEB_MESH); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, lbs_mesh_get_channel(priv)); @@ -924,7 +912,6 @@ static int lbs_mesh_stop(struct net_device *dev) if (!lbs_iface_active(priv)) lbs_stop_iface(priv); - lbs_deb_leave(LBS_DEB_MESH); return 0; } @@ -939,7 +926,6 @@ static int lbs_mesh_dev_open(struct net_device *dev) struct lbs_private *priv = dev->ml_priv; int ret = 0; - lbs_deb_enter(LBS_DEB_NET); if (!priv->iface_running) { ret = lbs_start_iface(priv); if (ret) @@ -965,7 +951,6 @@ static int lbs_mesh_dev_open(struct net_device *dev) lbs_mesh_get_channel(priv)); out: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } @@ -989,8 +974,6 @@ static int lbs_add_mesh(struct lbs_private *priv) struct wireless_dev *mesh_wdev; int ret = 0; - lbs_deb_enter(LBS_DEB_MESH); - /* Allocate a virtual mesh device */ mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!mesh_wdev) { @@ -1048,7 +1031,6 @@ err_free_wdev: kfree(mesh_wdev); done: - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } @@ -1060,7 +1042,6 @@ void lbs_remove_mesh(struct lbs_private *priv) if (!mesh_dev) return; - lbs_deb_enter(LBS_DEB_MESH); netif_stop_queue(mesh_dev); netif_carrier_off(mesh_dev); sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); @@ -1069,7 +1050,6 @@ void lbs_remove_mesh(struct lbs_private *priv) priv->mesh_dev = NULL; kfree(mesh_dev->ieee80211_ptr); free_netdev(mesh_dev); - lbs_deb_leave(LBS_DEB_MESH); } @@ -1108,15 +1088,15 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, * Ethtool related */ -static const char * const mesh_stat_strings[] = { - "drop_duplicate_bcast", - "drop_ttl_zero", - "drop_no_fwd_route", - "drop_no_buffers", - "fwded_unicast_cnt", - "fwded_bcast_cnt", - "drop_blind_table", - "tx_failed_cnt" +static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = { + "drop_duplicate_bcast", + "drop_ttl_zero", + "drop_no_fwd_route", + "drop_no_buffers", + "fwded_unicast_cnt", + "fwded_bcast_cnt", + "drop_blind_table", + "tx_failed_cnt" }; void lbs_mesh_ethtool_get_stats(struct net_device *dev, @@ -1126,8 +1106,6 @@ void lbs_mesh_ethtool_get_stats(struct net_device *dev, struct cmd_ds_mesh_access mesh_access; int ret; - lbs_deb_enter(LBS_DEB_ETHTOOL); - /* Get Mesh Statistics */ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access); @@ -1153,8 +1131,6 @@ void lbs_mesh_ethtool_get_stats(struct net_device *dev, data[5] = priv->mstats.fwd_bcast_cnt; data[6] = priv->mstats.drop_blind; data[7] = priv->mstats.tx_failed_cnt; - - lbs_deb_enter(LBS_DEB_ETHTOOL); } int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset) @@ -1170,18 +1146,9 @@ int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset) void lbs_mesh_ethtool_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *s) { - int i; - - lbs_deb_enter(LBS_DEB_ETHTOOL); - switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < MESH_STATS_NUM; i++) { - memcpy(s + i * ETH_GSTRING_LEN, - mesh_stat_strings[i], - ETH_GSTRING_LEN); - } + memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings)); break; } - lbs_deb_enter(LBS_DEB_ETHTOOL); } diff --git a/drivers/net/wireless/marvell/libertas/rx.c b/drivers/net/wireless/marvell/libertas/rx.c index e446fed7b345..7586ff681b23 100644 --- a/drivers/net/wireless/marvell/libertas/rx.c +++ b/drivers/net/wireless/marvell/libertas/rx.c @@ -65,8 +65,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - lbs_deb_enter(LBS_DEB_RX); - BUG_ON(!skb); skb->ip_summed = CHECKSUM_NONE; @@ -158,7 +156,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_process_rxed_packet); @@ -221,8 +218,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, struct rx_radiotap_hdr radiotap_hdr; struct rx_radiotap_hdr *pradiotap_hdr; - lbs_deb_enter(LBS_DEB_RX); - p_rx_pkt = (struct rx80211packethdr *) skb->data; prxpd = &p_rx_pkt->rx_pd; @@ -262,7 +257,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, goto done; } - pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); + pradiotap_hdr = skb_push(skb, sizeof(struct rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); @@ -281,6 +276,5 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, ret = 0; done: - lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/marvell/libertas/tx.c b/drivers/net/wireless/marvell/libertas/tx.c index c025f9c18282..723ba5fd0bfe 100644 --- a/drivers/net/wireless/marvell/libertas/tx.c +++ b/drivers/net/wireless/marvell/libertas/tx.c @@ -70,8 +70,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) uint16_t pkt_len; netdev_tx_t ret = NETDEV_TX_OK; - lbs_deb_enter(LBS_DEB_TX); - /* We need to protect against the queues being restarted before we get round to stopping them */ spin_lock_irqsave(&priv->driver_lock, flags); @@ -166,7 +164,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->driver_lock, flags); wake_up(&priv->waitq); - lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index d80333117989..81228bf73043 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -260,7 +260,7 @@ static void lbtf_tx_work(struct work_struct *work) len = skb->len; info = IEEE80211_SKB_CB(skb); - txpd = (struct txpd *) skb_push(skb, sizeof(struct txpd)); + txpd = skb_push(skb, sizeof(struct txpd)); if (priv->surpriseremoved) { dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 366eb4991a7d..238accfe4f41 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -128,9 +128,6 @@ void mwifiex_dfs_cac_work_queue(struct work_struct *work) container_of(delayed_work, struct mwifiex_private, dfs_cac_work); - if (WARN_ON(!priv)) - return; - chandef = priv->dfs_chandef; if (priv->wdev.cac_started) { mwifiex_dbg(priv->adapter, MSG, @@ -289,9 +286,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) container_of(delayed_work, struct mwifiex_private, dfs_chan_sw_work); - if (WARN_ON(!priv)) - return; - bss_cfg = &priv->bss_cfg; if (!bss_cfg->beacon_period) { mwifiex_dbg(priv->adapter, ERROR, diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index c174e79e6df2..16c77c27f1b6 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -653,11 +653,13 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, void mwifiex_11n_delba(struct mwifiex_private *priv, int tid) { struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + unsigned long flags; + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); if (list_empty(&priv->rx_reorder_tbl_ptr)) { dev_dbg(priv->adapter->dev, "mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n"); - return; + goto exit; } list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { @@ -666,9 +668,11 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid) "Send delba to tid=%d, %pM\n", tid, rx_reor_tbl_ptr->ta); mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0); - return; + goto exit; } } +exit: + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); } /* @@ -764,14 +768,9 @@ void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra) return; spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); - list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) { - if (!memcmp(tbl->ra, ra, ETH_ALEN)) { - spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, - flags); + list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) + if (!memcmp(tbl->ra, ra, ETH_ALEN)) mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl); - spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); - } - } spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); return; diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index a75013ac84d7..042a1d07f686 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -62,7 +62,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, }; struct tx_packet_hdr *tx_header; - tx_header = (void *)skb_put(skb_aggr, sizeof(*tx_header)); + tx_header = skb_put(skb_aggr, sizeof(*tx_header)); /* Copy DA and SA */ dt_offset = 2 * ETH_ALEN; @@ -81,7 +81,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); /* Add payload */ - memcpy(skb_put(skb_aggr, skb_src->len), skb_src->data, skb_src->len); + skb_put_data(skb_aggr, skb_src->data, skb_src->len); /* Add padding for new MSDU to start from 4 byte boundary */ *pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4; @@ -164,7 +164,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, int pad = 0, aggr_num = 0, ret; struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; - int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN; + int headroom = adapter->intf_hdr_len; skb_src = skb_peek(&pra_list->skb_head); if (!skb_src) { @@ -250,15 +250,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, return 0; } + if (skb_src) + tx_param.next_pkt_len = skb_src->len + sizeof(struct txpd); + else + tx_param.next_pkt_len = 0; + if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb_aggr, NULL); + skb_aggr, &tx_param); } else { - if (skb_src) - tx_param.next_pkt_len = - skb_src->len + sizeof(struct txpd); - else - tx_param.next_pkt_len = 0; ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb_aggr, &tx_param); diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 7ec06bf13413..06ad2d50f9b0 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -176,12 +176,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type)); /* Add packet data and address4 */ - memcpy(skb_put(skb, sizeof(struct ieee80211_hdr_3addr)), buf, - sizeof(struct ieee80211_hdr_3addr)); - memcpy(skb_put(skb, ETH_ALEN), addr, ETH_ALEN); - memcpy(skb_put(skb, len - sizeof(struct ieee80211_hdr_3addr)), - buf + sizeof(struct ieee80211_hdr_3addr), - len - sizeof(struct ieee80211_hdr_3addr)); + skb_put_data(skb, buf, sizeof(struct ieee80211_hdr_3addr)); + skb_put_data(skb, addr, ETH_ALEN); + skb_put_data(skb, buf + sizeof(struct ieee80211_hdr_3addr), + len - sizeof(struct ieee80211_hdr_3addr)); skb->priority = LOW_PRIO_TID; __net_timestamp(skb); @@ -894,24 +892,20 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_STA); priv->bss_role = MWIFIEX_BSS_ROLE_STA; - priv->bss_type = MWIFIEX_BSS_TYPE_STA; break; case NL80211_IFTYPE_P2P_CLIENT: priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_STA; - priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; case NL80211_IFTYPE_P2P_GO: priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_UAP; - priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; case NL80211_IFTYPE_AP: priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_UAP); - priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; break; default: @@ -1983,7 +1977,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, if (mwifiex_set_secure_params(priv, bss_cfg, params)) { mwifiex_dbg(priv->adapter, ERROR, - "Failed to parse secuirty parameters!\n"); + "Failed to parse security parameters!\n"); goto out; } @@ -2964,10 +2958,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, if (!dev) { mwifiex_dbg(adapter, ERROR, "no memory available for netdevice\n"); - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_alloc_netdev; } mwifiex_init_priv_params(priv, dev); @@ -2976,11 +2968,11 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, HostCmd_ACT_GEN_SET, 0, NULL, true); if (ret) - return ERR_PTR(ret); + goto err_set_bss_mode; ret = mwifiex_sta_init_cmd(priv, false, false); if (ret) - return ERR_PTR(ret); + goto err_sta_init; mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv); if (adapter->is_hw_11ac_capable) @@ -3011,31 +3003,14 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, SET_NETDEV_DEV(dev, adapter->dev); - /* Register network device */ - if (register_netdevice(dev)) { - mwifiex_dbg(adapter, ERROR, - "cannot register virtual network device\n"); - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - priv->netdev = NULL; - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - return ERR_PTR(-EFAULT); - } - priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC%s", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1, name); if (!priv->dfs_cac_workqueue) { - mwifiex_dbg(adapter, ERROR, - "cannot register virtual network device\n"); - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - priv->netdev = NULL; - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - return ERR_PTR(-ENOMEM); + mwifiex_dbg(adapter, ERROR, "cannot alloc DFS CAC queue\n"); + ret = -ENOMEM; + goto err_alloc_cac; } INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); @@ -3044,22 +3019,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, WQ_HIGHPRI | WQ_UNBOUND | WQ_MEM_RECLAIM, 1, name); if (!priv->dfs_chan_sw_workqueue) { - mwifiex_dbg(adapter, ERROR, - "cannot register virtual network device\n"); - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - priv->netdev = NULL; - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - destroy_workqueue(priv->dfs_cac_workqueue); - priv->dfs_cac_workqueue = NULL; - return ERR_PTR(-ENOMEM); + mwifiex_dbg(adapter, ERROR, "cannot alloc DFS channel sw queue\n"); + ret = -ENOMEM; + goto err_alloc_chsw; } INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, mwifiex_dfs_chan_sw_work_queue); - sema_init(&priv->async_sem, 1); + mutex_init(&priv->async_mutex); + + /* Register network device */ + if (register_netdevice(dev)) { + mwifiex_dbg(adapter, ERROR, "cannot register network device\n"); + ret = -EFAULT; + goto err_reg_netdev; + } mwifiex_dbg(adapter, INFO, "info: %s: Marvell 802.11 Adapter\n", dev->name); @@ -3081,11 +3056,29 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, adapter->curr_iface_comb.p2p_intf++; break; default: + /* This should be dead code; checked above */ mwifiex_dbg(adapter, ERROR, "type not supported\n"); return ERR_PTR(-EINVAL); } return &priv->wdev; + +err_reg_netdev: + destroy_workqueue(priv->dfs_chan_sw_workqueue); + priv->dfs_chan_sw_workqueue = NULL; +err_alloc_chsw: + destroy_workqueue(priv->dfs_cac_workqueue); + priv->dfs_cac_workqueue = NULL; +err_alloc_cac: + free_netdev(dev); + priv->netdev = NULL; +err_sta_init: +err_set_bss_mode: +err_alloc_netdev: + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); diff --git a/drivers/net/wireless/marvell/mwifiex/cfp.c b/drivers/net/wireless/marvell/mwifiex/cfp.c index 1ff22055e54f..6e2994308526 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfp.c +++ b/drivers/net/wireless/marvell/mwifiex/cfp.c @@ -350,7 +350,7 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq) } } if (i == sband->n_channels) { - mwifiex_dbg(priv->adapter, ERROR, + mwifiex_dbg(priv->adapter, WARN, "%s: cannot find cfp by band %d\t" "& channel=%d freq=%d\n", __func__, band, channel, freq); diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 0c3b217247b1..8dad52886034 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -258,10 +258,10 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, if (ret == -EBUSY) cmd_node->cmd_skb = NULL; } else { - skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); + skb_push(cmd_node->cmd_skb, adapter->intf_hdr_len); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, cmd_node->cmd_skb, NULL); - skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); + skb_pull(cmd_node->cmd_skb, adapter->intf_hdr_len); } if (ret == -1) { @@ -351,10 +351,10 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) if (ret != -EBUSY) dev_kfree_skb_any(sleep_cfm_tmp); } else { - skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); + skb_push(adapter->sleep_cfm, adapter->intf_hdr_len); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, adapter->sleep_cfm, NULL); - skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); + skb_pull(adapter->sleep_cfm, adapter->intf_hdr_len); } if (ret == -1) { @@ -622,8 +622,7 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, return -1; } - memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)), - 0, sizeof(struct host_cmd_ds_command)); + skb_put_zero(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)); cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); cmd_ptr->command = cpu_to_le16(cmd_no); @@ -761,8 +760,6 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) } cmd_node = list_first_entry(&adapter->cmd_pending_q, struct cmd_ctrl_node, list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); priv = cmd_node->priv; @@ -771,11 +768,12 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) mwifiex_dbg(adapter, ERROR, "%s: cannot send cmd in sleep state,\t" "this should not happen\n", __func__); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); return ret; } - spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); @@ -1056,12 +1054,10 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) list_for_each_entry_safe(cmd_node, tmp_node, &adapter->cmd_pending_q, list) { list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); if (cmd_node->wait_q_enabled) adapter->cmd_wait_q.status = -1; mwifiex_recycle_cmd_node(adapter, cmd_node); - spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); } spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index ae2b69db5994..f6f105a7d3ff 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -1046,6 +1046,5 @@ mwifiex_debugfs_init(void) void mwifiex_debugfs_remove(void) { - if (mwifiex_dfs_dir) - debugfs_remove(mwifiex_dfs_dir); + debugfs_remove(mwifiex_dfs_dir); } diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 6cf9ab9133ea..9e75522d248a 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -247,11 +247,6 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define MWIFIEX_DEF_AMPDU IEEE80211_HT_AMPDU_PARM_FACTOR -#define GET_RXSTBC(x) (x & IEEE80211_HT_CAP_RX_STBC) -#define MWIFIEX_RX_STBC1 0x0100 -#define MWIFIEX_RX_STBC12 0x0200 -#define MWIFIEX_RX_STBC123 0x0300 - /* dev_cap bitmap * BIT * 0-16 reserved @@ -405,6 +400,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 #define HostCmd_CMD_CHAN_REGION_CFG 0x0242 +#define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251 #define PROTOCOL_NO_SECURITY 0x01 #define PROTOCOL_STATIC_WEP 0x02 @@ -2268,6 +2264,14 @@ struct host_cmd_ds_chan_region_cfg { __le16 action; } __packed; +struct host_cmd_ds_pkt_aggr_ctrl { + __le16 action; + __le16 enable; + __le16 tx_aggr_max_size; + __le16 tx_aggr_max_num; + __le16 tx_aggr_align; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2343,6 +2347,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_wakeup_reason hs_wakeup_reason; struct host_cmd_ds_gtk_rekey_params rekey; struct host_cmd_ds_chan_region_cfg reg_cfg; + struct host_cmd_ds_pkt_aggr_ctrl pkt_aggr_ctrl; } params; } __packed; diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 756948385b60..3ecb59f7405b 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -217,6 +217,11 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) else adapter->data_sent = false; + if (adapter->iface_type == MWIFIEX_USB) + adapter->intf_hdr_len = 0; + else + adapter->intf_hdr_len = INTF_HEADER_LEN; + adapter->cmd_resp_received = false; adapter->event_received = false; adapter->data_received = false; @@ -409,11 +414,6 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) static void mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) { - if (!adapter) { - pr_err("%s: adapter is NULL\n", __func__); - return; - } - del_timer(&adapter->wakeup_timer); mwifiex_cancel_all_pending_cmd(adapter); wake_up_interruptible(&adapter->cmd_wait_q.wait); @@ -439,7 +439,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) struct mwifiex_private *priv; s32 i, j; - spin_lock_init(&adapter->mwifiex_lock); spin_lock_init(&adapter->int_lock); spin_lock_init(&adapter->main_proc_lock); spin_lock_init(&adapter->mwifiex_cmd_lock); @@ -670,8 +669,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) mwifiex_clean_auto_tdls(priv); mwifiex_abort_cac(priv); - mwifiex_clean_txrx(priv); - mwifiex_delete_bss_prio_tbl(priv); + mwifiex_free_priv(priv); } } @@ -694,11 +692,8 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); - spin_lock(&adapter->mwifiex_lock); - mwifiex_adapter_cleanup(adapter); - spin_unlock(&adapter->mwifiex_lock); adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY; } diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 39b6b5e3f6e0..f2600b827e81 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -44,6 +44,10 @@ bool mfg_mode; module_param(mfg_mode, bool, 0); MODULE_PARM_DESC(mfg_mode, "manufacturing mode enable:1, disable:0"); +bool aggr_ctrl; +module_param(aggr_ctrl, bool, 0000); +MODULE_PARM_DESC(aggr_ctrl, "usb tx aggreataon enable:1, disable:0"); + /* * This function registers the device and performs all the necessary * initializations. diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index bb2a467d8b13..f8cf3079ac7d 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -60,6 +60,7 @@ extern const char driver_version[]; extern bool mfg_mode; +extern bool aggr_ctrl; struct mwifiex_adapter; struct mwifiex_private; @@ -628,7 +629,7 @@ struct mwifiex_private { struct dentry *dfs_dev_dir; #endif u16 current_key_index; - struct semaphore async_sem; + struct mutex async_mutex; struct cfg80211_scan_request *scan_request; u8 cfg_bssid[6]; struct wps wps; @@ -798,6 +799,18 @@ struct mwifiex_auto_tdls_peer { u8 do_setup; }; +#define MWIFIEX_TYPE_AGGR_DATA_V2 11 +#define MWIFIEX_BUS_AGGR_MODE_LEN_V2 (2) +#define MWIFIEX_BUS_AGGR_MAX_LEN 16000 +#define MWIFIEX_BUS_AGGR_MAX_NUM 10 +struct bus_aggr_params { + u16 enable; + u16 mode; + u16 tx_aggr_max_size; + u16 tx_aggr_max_num; + u16 tx_aggr_align; +}; + struct mwifiex_if_ops { int (*init_if) (struct mwifiex_adapter *); void (*cleanup_if) (struct mwifiex_adapter *); @@ -849,6 +862,7 @@ struct mwifiex_adapter { u8 perm_addr[ETH_ALEN]; bool surprise_removed; u32 fw_release_number; + u8 intf_hdr_len; u16 init_wait_q_woken; wait_queue_head_t init_wait_q; void *card; @@ -870,8 +884,6 @@ struct mwifiex_adapter { bool rx_locked; bool main_locked; struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; - /* spin lock for init/shutdown */ - spinlock_t mwifiex_lock; /* spin lock for main process */ spinlock_t main_proc_lock; u32 mwifiex_processing; @@ -1017,6 +1029,8 @@ struct mwifiex_adapter { /* Wake-on-WLAN (WoWLAN) */ int irq_wakeup; bool wake_by_wifi; + /* Aggregation parameters*/ + struct bus_aggr_params bus_aggr; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); @@ -1235,7 +1249,8 @@ mwifiex_queuing_ra_based(struct mwifiex_private *priv) * Currently we assume if we are in Infra, then DA=RA. This might not be * true in the future */ - if ((priv->bss_mode == NL80211_IFTYPE_STATION) && + if ((priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) && (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) return false; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index ac62bce50e96..b53ecf1eddda 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -370,7 +370,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) * PCIe and HW. */ mwifiex_shutdown_sw(adapter); - adapter->surprise_removed = true; clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); } else { @@ -378,7 +377,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) * after performing FLR respectively. Reconfigure the software * and firmware including firmware redownload */ - adapter->surprise_removed = false; ret = mwifiex_reinit_sw(adapter); if (ret) { dev_err(&pdev->dev, "reinit failed: %d\n", ret); @@ -1391,7 +1389,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) * first 2 bytes for len, next 2 bytes is for type */ rx_len = get_unaligned_le16(skb_data->data); - if (WARN_ON(rx_len <= INTF_HEADER_LEN || + if (WARN_ON(rx_len <= adapter->intf_hdr_len || rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) { mwifiex_dbg(adapter, ERROR, "Invalid RX len %d, Rd=%#x, Wr=%#x\n", @@ -1402,7 +1400,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) mwifiex_dbg(adapter, DATA, "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", card->rxbd_rdptr, wrptr, rx_len); - skb_pull(skb_data, INTF_HEADER_LEN); + skb_pull(skb_data, adapter->intf_hdr_len); if (adapter->rx_work_enabled) { skb_queue_tail(&adapter->rx_data_q, skb_data); adapter->data_received = true; @@ -1736,7 +1734,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) MWIFIEX_MAX_DELAY_COUNT); mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_FROMDEVICE); - skb_pull(skb, INTF_HEADER_LEN); + skb_pull(skb, adapter->intf_hdr_len); while (reg->sleep_cookie && (count++ < 10) && mwifiex_pcie_ok_to_access_hw(adapter)) usleep_range(50, 60); @@ -1749,12 +1747,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) } memcpy(adapter->upld_buf, skb->data, min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, adapter->intf_hdr_len); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, PCI_DMA_FROMDEVICE)) return -1; } else if (mwifiex_pcie_ok_to_access_hw(adapter)) { - skb_pull(skb, INTF_HEADER_LEN); + skb_pull(skb, adapter->intf_hdr_len); adapter->curr_cmd->resp_skb = skb; adapter->cmd_resp_received = true; /* Take the pointer and set it to CMD node and will @@ -1791,7 +1789,7 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, if (skb) { card->cmdrsp_buf = skb; - skb_push(card->cmdrsp_buf, INTF_HEADER_LEN); + skb_push(card->cmdrsp_buf, adapter->intf_hdr_len); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, PCI_DMA_FROMDEVICE)) return -1; @@ -1856,14 +1854,15 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) desc = card->evtbd_ring[rdptr]; memset(desc, 0, sizeof(*desc)); - event = get_unaligned_le32(&skb_cmd->data[INTF_HEADER_LEN]); + event = get_unaligned_le32( + &skb_cmd->data[adapter->intf_hdr_len]); adapter->event_cause = event; /* The first 4bytes will be the event transfer header len is 2 bytes followed by type which is 2 bytes */ memcpy(&data_len, skb_cmd->data, sizeof(__le16)); evt_len = le16_to_cpu(data_len); skb_trim(skb_cmd, evt_len); - skb_pull(skb_cmd, INTF_HEADER_LEN); + skb_pull(skb_cmd, adapter->intf_hdr_len); mwifiex_dbg(adapter, EVENT, "info: Event length: %d\n", evt_len); @@ -1922,7 +1921,7 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, } if (!card->evt_buf_list[rdptr]) { - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, adapter->intf_hdr_len); skb_put(skb, MAX_EVENT_SIZE - skb->len); if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, @@ -2380,11 +2379,6 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) struct pcie_service_card *card; struct mwifiex_adapter *adapter; - if (!pdev) { - pr_err("info: %s: pdev is NULL\n", __func__); - goto exit; - } - card = pci_get_drvdata(pdev); if (!card->adapter) { @@ -2822,6 +2816,13 @@ static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter) mwifiex_upload_device_dump(adapter, drv_info, drv_info_size); } +static void mwifiex_pcie_card_reset_work(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + pci_reset_function(card->dev); +} + static void mwifiex_pcie_work(struct work_struct *work) { struct pcie_service_card *card = @@ -2830,6 +2831,9 @@ static void mwifiex_pcie_work(struct work_struct *work) if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags)) mwifiex_pcie_device_dump_work(card->adapter); + if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, + &card->work_flags)) + mwifiex_pcie_card_reset_work(card->adapter); } /* This function dumps FW information */ @@ -2837,12 +2841,72 @@ static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags)) - return; + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + schedule_work(&card->work); +} + +static void mwifiex_pcie_card_reset(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags)) + schedule_work(&card->work); +} + +static int mwifiex_pcie_alloc_buffers(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int ret; + + card->cmdrsp_buf = NULL; + ret = mwifiex_pcie_create_txbd_ring(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n"); + goto err_cre_txbd; + } + + ret = mwifiex_pcie_create_rxbd_ring(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n"); + goto err_cre_rxbd; + } + + ret = mwifiex_pcie_create_evtbd_ring(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n"); + goto err_cre_evtbd; + } - set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); + ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n"); + goto err_alloc_cmdbuf; + } - schedule_work(&card->work); + if (reg->sleep_cookie) { + ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n"); + goto err_alloc_cookie; + } + } else { + card->sleep_cookie_vbase = NULL; + } + + return 0; + +err_alloc_cookie: + mwifiex_pcie_delete_cmdrsp_buf(adapter); +err_alloc_cmdbuf: + mwifiex_pcie_delete_evtbd_ring(adapter); +err_cre_evtbd: + mwifiex_pcie_delete_rxbd_ring(adapter); +err_cre_rxbd: + mwifiex_pcie_delete_txbd_ring(adapter); +err_cre_txbd: + return ret; } static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter) @@ -2862,20 +2926,12 @@ static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter) /* * This function initializes the PCI-E host memory space, WCB rings, etc. - * - * The following initializations steps are followed - - * - Allocate TXBD ring buffers - * - Allocate RXBD ring buffers - * - Allocate event BD ring buffers - * - Allocate command response ring buffer - * - Allocate sleep cookie buffer */ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; int ret; struct pci_dev *pdev = card->dev; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; pci_set_drvdata(pdev, card); @@ -2924,37 +2980,13 @@ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter) pr_notice("PCI memory map Virt0: %p PCI memory map Virt2: %p\n", card->pci_mmap, card->pci_mmap1); - card->cmdrsp_buf = NULL; - ret = mwifiex_pcie_create_txbd_ring(adapter); - if (ret) - goto err_cre_txbd; - ret = mwifiex_pcie_create_rxbd_ring(adapter); + ret = mwifiex_pcie_alloc_buffers(adapter); if (ret) - goto err_cre_rxbd; - ret = mwifiex_pcie_create_evtbd_ring(adapter); - if (ret) - goto err_cre_evtbd; - ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); - if (ret) - goto err_alloc_cmdbuf; - if (reg->sleep_cookie) { - ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); - if (ret) - goto err_alloc_cookie; - } else { - card->sleep_cookie_vbase = NULL; - } - return ret; + goto err_alloc_buffers; -err_alloc_cookie: - mwifiex_pcie_delete_cmdrsp_buf(adapter); -err_alloc_cmdbuf: - mwifiex_pcie_delete_evtbd_ring(adapter); -err_cre_evtbd: - mwifiex_pcie_delete_rxbd_ring(adapter); -err_cre_rxbd: - mwifiex_pcie_delete_txbd_ring(adapter); -err_cre_txbd: + return 0; + +err_alloc_buffers: pci_iounmap(pdev, card->pci_mmap1); err_iomap2: pci_release_region(pdev, 2); @@ -3168,73 +3200,25 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) card->adapter = NULL; } -/* This function initializes the PCI-E host memory space, WCB rings, etc. - * - * The following initializations steps are followed - - * - Allocate TXBD ring buffers - * - Allocate RXBD ring buffers - * - Allocate event BD ring buffers - * - Allocate command response ring buffer - * - Allocate sleep cookie buffer - * Part of mwifiex_init_pcie(), not reset the PCIE registers +/* + * This function initializes the PCI-E host memory space, WCB rings, etc., + * similar to mwifiex_init_pcie(), but without resetting PCI-E state. */ static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; int ret; struct pci_dev *pdev = card->dev; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; /* tx_buf_size might be changed to 3584 by firmware during * data transfer, we should reset it to default size. */ adapter->tx_buf_size = card->pcie.tx_buf_size; - card->cmdrsp_buf = NULL; - ret = mwifiex_pcie_create_txbd_ring(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n"); - goto err_cre_txbd; - } - - ret = mwifiex_pcie_create_rxbd_ring(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n"); - goto err_cre_rxbd; - } - - ret = mwifiex_pcie_create_evtbd_ring(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n"); - goto err_cre_evtbd; - } - - ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n"); - goto err_alloc_cmdbuf; - } - - if (reg->sleep_cookie) { - ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n"); - goto err_alloc_cookie; - } - } else { - card->sleep_cookie_vbase = NULL; - } - return; + ret = mwifiex_pcie_alloc_buffers(adapter); + if (!ret) + return; -err_alloc_cookie: - mwifiex_pcie_delete_cmdrsp_buf(adapter); -err_alloc_cmdbuf: - mwifiex_pcie_delete_evtbd_ring(adapter); -err_cre_evtbd: - mwifiex_pcie_delete_rxbd_ring(adapter); -err_cre_rxbd: - mwifiex_pcie_delete_txbd_ring(adapter); -err_cre_txbd: pci_iounmap(pdev, card->pci_mmap1); } @@ -3274,6 +3258,7 @@ static struct mwifiex_if_ops pcie_ops = { .cleanup_mpa_buf = NULL, .init_fw_port = mwifiex_pcie_init_fw_port, .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, + .card_reset = mwifiex_pcie_card_reset, .reg_dump = mwifiex_pcie_reg_dump, .device_dump = mwifiex_pcie_device_dump, .down_dev = mwifiex_pcie_down_dev, diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index ce6936d0c5c0..ae9630b49342 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2809,7 +2809,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, { int ret; - if (down_interruptible(&priv->async_sem)) { + if (mutex_lock_interruptible(&priv->async_mutex)) { mwifiex_dbg(priv->adapter, ERROR, "%s: acquire semaphore fail\n", __func__); @@ -2825,7 +2825,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, /* Normal scan */ ret = mwifiex_scan_networks(priv, NULL); - up(&priv->async_sem); + mutex_unlock(&priv->async_mutex); return ret; } diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 0af1c6733c92..f81a006668f3 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1125,7 +1125,7 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, data = skb->data; total_pkt_len = skb->len; - while (total_pkt_len >= (SDIO_HEADER_OFFSET + INTF_HEADER_LEN)) { + while (total_pkt_len >= (SDIO_HEADER_OFFSET + adapter->intf_hdr_len)) { if (total_pkt_len < adapter->sdio_rx_block_size) break; blk_num = *(data + BLOCK_NUMBER_OFFSET); @@ -1152,7 +1152,7 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, break; skb_put(skb_deaggr, pkt_len); memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len); - skb_pull(skb_deaggr, INTF_HEADER_LEN); + skb_pull(skb_deaggr, adapter->intf_hdr_len); mwifiex_handle_rx_packet(adapter, skb_deaggr); data += blk_size; @@ -1178,7 +1178,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) { skb_trim(skb, pkt_len); - skb_pull(skb, INTF_HEADER_LEN); + skb_pull(skb, adapter->intf_hdr_len); } switch (upld_typ) { @@ -1537,7 +1537,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) rx_len = card->mp_regs[reg->cmd_rd_len_1] << 8; rx_len |= (u16)card->mp_regs[reg->cmd_rd_len_0]; rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE); - if (rx_len <= INTF_HEADER_LEN || + if (rx_len <= adapter->intf_hdr_len || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > MWIFIEX_RX_DATA_BUF_SIZE) return -1; @@ -1635,7 +1635,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) rx_blocks = (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - 1) / MWIFIEX_SDIO_BLOCK_SIZE; - if (rx_len <= INTF_HEADER_LEN || + if (rx_len <= adapter->intf_hdr_len || (card->mpa_rx.enabled && ((rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > card->mpa_rx.buf_size))) { @@ -1896,7 +1896,7 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, adapter->cmd_sent = true; /* Type must be MWIFIEX_TYPE_CMD */ - if (pkt_len <= INTF_HEADER_LEN || + if (pkt_len <= adapter->intf_hdr_len || pkt_len > MWIFIEX_UPLD_SIZE) mwifiex_dbg(adapter, ERROR, "%s: payload=%p, nb=%d\n", @@ -2533,12 +2533,8 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags)) - return; - - set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); - - schedule_work(&card->work); + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags)) + schedule_work(&card->work); } /* This function dumps FW information */ @@ -2546,11 +2542,9 @@ static void mwifiex_sdio_device_dump(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags)) - return; - - set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); - schedule_work(&card->work); + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + schedule_work(&card->work); } /* Function to dump SDIO function registers and SDIO scratch registers in case diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 83916c1439af..534d94a206a5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -2064,6 +2064,15 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_11AC_CFG: ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf); break; + case HostCmd_CMD_PACKET_AGGR_CTRL: + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->params.pkt_aggr_ctrl.action = cpu_to_le16(cmd_action); + cmd_ptr->params.pkt_aggr_ctrl.enable = + cpu_to_le16(*(u16 *)data_buf); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_pkt_aggr_ctrl) + + S_DS_GEN); + break; case HostCmd_CMD_P2P_MODE_CFG: cmd_ptr->command = cpu_to_le16(cmd_no); cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action); @@ -2241,6 +2250,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) enum state_11d_t state_11d; struct mwifiex_ds_11n_tx_cfg tx_cfg; u8 sdio_sp_rx_aggr_enable; + u16 packet_aggr_enable; int data; if (first_sta) { @@ -2387,6 +2397,14 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) "11D: failed to enable 11D\n"); } + /* Pacekt aggregation handshake with firmware */ + if (aggr_ctrl) { + packet_aggr_enable = true; + mwifiex_send_cmd(priv, HostCmd_CMD_PACKET_AGGR_CTRL, + HostCmd_ACT_GEN_SET, 0, + &packet_aggr_enable, true); + } + /* Send cmd to FW to configure 11n specific configuration * (Short GI, Channel BW, Green field support etc.) for transmit */ diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index f1d1f56fc23f..2945775e83c5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1154,6 +1154,27 @@ static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv, return 0; } +static int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_pkt_aggr_ctrl *pkt_aggr_ctrl = + &resp->params.pkt_aggr_ctrl; + struct mwifiex_adapter *adapter = priv->adapter; + + adapter->bus_aggr.enable = le16_to_cpu(pkt_aggr_ctrl->enable); + if (adapter->bus_aggr.enable) + adapter->intf_hdr_len = INTF_HEADER_LEN; + adapter->bus_aggr.mode = MWIFIEX_BUS_AGGR_MODE_LEN_V2; + adapter->bus_aggr.tx_aggr_max_size = + le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_size); + adapter->bus_aggr.tx_aggr_max_num = + le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_num); + adapter->bus_aggr.tx_aggr_align = + le16_to_cpu(pkt_aggr_ctrl->tx_aggr_align); + + return 0; +} + /* * This function handles the command responses. * @@ -1255,6 +1276,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_11AC_CFG: break; + case HostCmd_CMD_PACKET_AGGR_CTRL: + ret = mwifiex_ret_pkt_aggr_ctrl(priv, resp); + break; case HostCmd_CMD_P2P_MODE_CFG: ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf); break; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_tx.c b/drivers/net/wireless/marvell/mwifiex/sta_tx.c index f6683ea6bd5d..620f8650a742 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_tx.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_tx.c @@ -49,8 +49,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); unsigned int pad; u16 pkt_type, pkt_offset; - int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : - INTF_HEADER_LEN; + int hroom = adapter->intf_hdr_len; if (!skb->len) { mwifiex_dbg(adapter, ERROR, @@ -116,7 +115,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset); - /* make space for INTF_HEADER_LEN */ + /* make space for adapter->intf_hdr_len */ skb_push(skb, hroom); if (!local_tx_pd->tx_control) @@ -165,8 +164,9 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) memset(tx_info, 0, sizeof(*tx_info)); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; - tx_info->pkt_len = data_len - (sizeof(struct txpd) + INTF_HEADER_LEN); - skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); + tx_info->pkt_len = data_len - + (sizeof(struct txpd) + adapter->intf_hdr_len); + skb_reserve(skb, sizeof(struct txpd) + adapter->intf_hdr_len); skb_push(skb, sizeof(struct txpd)); local_tx_pd = (struct txpd *) skb->data; @@ -177,11 +177,11 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; + skb_push(skb, adapter->intf_hdr_len); if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, skb, NULL); } else { - skb_push(skb, INTF_HEADER_LEN); tx_param.next_pkt_len = 0; ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, &tx_param); diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 7d0d3ff3dd4c..39cd677d4159 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -55,11 +55,8 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; } else { tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list; - if (!list_empty(tid_list)) - ra_list = list_first_entry(tid_list, - struct mwifiex_ra_list_tbl, list); - else - ra_list = NULL; + ra_list = list_first_entry_or_null(tid_list, + struct mwifiex_ra_list_tbl, list); tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT; } @@ -161,7 +158,7 @@ static void mwifiex_tdls_add_aid(struct mwifiex_private *priv, u8 *pos; assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf; - pos = (void *)skb_put(skb, 4); + pos = skb_put(skb, 4); *pos++ = WLAN_EID_AID; *pos++ = 2; memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id)); @@ -175,7 +172,7 @@ static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv, struct ieee80211_vht_cap vht_cap; u8 *pos; - pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); *pos++ = WLAN_EID_VHT_CAPABILITY; *pos++ = sizeof(struct ieee80211_vht_cap); @@ -210,7 +207,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac, return 0; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2); *pos++ = WLAN_EID_HT_OPERATION; *pos++ = sizeof(struct ieee80211_ht_operation); ht_oper = (void *)pos; @@ -275,7 +272,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv, ap_vht_cap = bss_desc->bcn_vht_cap; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2); *pos++ = WLAN_EID_VHT_OPERATION; *pos++ = sizeof(struct ieee80211_vht_operation); vht_oper = (struct ieee80211_vht_operation *)pos; @@ -362,7 +359,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, { struct ieee_types_extcap *extcap; - extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap)); + extcap = skb_put(skb, sizeof(struct ieee_types_extcap)); extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY; extcap->ieee_hdr.len = 8; memset(extcap->ext_capab, 0, 8); @@ -375,7 +372,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb) { - u8 *pos = (void *)skb_put(skb, 3); + u8 *pos = skb_put(skb, 3); *pos++ = WLAN_EID_QOS_CAPA; *pos++ = 1; @@ -391,8 +388,7 @@ mwifiex_tdls_add_wmm_param_ie(struct mwifiex_private *priv, struct sk_buff *skb) u8 ac_be[] = {0x03, 0xa4, 0x00, 0x00}; u8 ac_bk[] = {0x27, 0xa4, 0x00, 0x00}; - wmm = (void *)skb_put(skb, sizeof(*wmm)); - memset(wmm, 0, sizeof(*wmm)); + wmm = skb_put_zero(skb, sizeof(*wmm)); wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; wmm->len = sizeof(*wmm) - 2; @@ -417,8 +413,8 @@ mwifiex_add_wmm_info_ie(struct mwifiex_private *priv, struct sk_buff *skb, { u8 *buf; - buf = (void *)skb_put(skb, MWIFIEX_TDLS_WMM_INFO_SIZE + - sizeof(struct ieee_types_header)); + buf = skb_put(skb, + MWIFIEX_TDLS_WMM_INFO_SIZE + sizeof(struct ieee_types_header)); *buf++ = WLAN_EID_VENDOR_SPECIFIC; *buf++ = 7; /* len */ @@ -435,7 +431,7 @@ static void mwifiex_tdls_add_bss_co_2040(struct sk_buff *skb) { struct ieee_types_bss_co_2040 *bssco; - bssco = (void *)skb_put(skb, sizeof(struct ieee_types_bss_co_2040)); + bssco = skb_put(skb, sizeof(struct ieee_types_bss_co_2040)); bssco->ieee_hdr.element_id = WLAN_EID_BSS_COEX_2040; bssco->ieee_hdr.len = sizeof(struct ieee_types_bss_co_2040) - sizeof(struct ieee_types_header); @@ -447,8 +443,8 @@ static void mwifiex_tdls_add_supported_chan(struct sk_buff *skb) struct ieee_types_generic *supp_chan; u8 chan_supp[] = {1, 11}; - supp_chan = (void *)skb_put(skb, (sizeof(struct ieee_types_header) + - sizeof(chan_supp))); + supp_chan = skb_put(skb, + (sizeof(struct ieee_types_header) + sizeof(chan_supp))); supp_chan->ieee_hdr.element_id = WLAN_EID_SUPPORTED_CHANNELS; supp_chan->ieee_hdr.len = sizeof(chan_supp); memcpy(supp_chan->data, chan_supp, sizeof(chan_supp)); @@ -459,8 +455,8 @@ static void mwifiex_tdls_add_oper_class(struct sk_buff *skb) struct ieee_types_generic *reg_class; u8 rc_list[] = {1, 1, 2, 3, 4, 12, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33}; - reg_class = (void *)skb_put(skb, (sizeof(struct ieee_types_header) + - sizeof(rc_list))); + reg_class = skb_put(skb, + (sizeof(struct ieee_types_header) + sizeof(rc_list))); reg_class->ieee_hdr.element_id = WLAN_EID_SUPPORTED_REGULATORY_CLASSES; reg_class->ieee_hdr.len = sizeof(rc_list); memcpy(reg_class->data, rc_list, sizeof(rc_list)); @@ -479,7 +475,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap; - tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); + tf = skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); memcpy(tf->da, peer, ETH_ALEN); memcpy(tf->sa, priv->curr_addr, ETH_ALEN); tf->ether_type = cpu_to_be16(ETH_P_TDLS); @@ -498,7 +494,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, return ret; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (void *)pos; @@ -538,7 +534,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, return ret; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (void *)pos; @@ -620,7 +616,7 @@ mwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, { struct ieee80211_tdls_lnkie *lnkid; - lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); + lnkid = skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); lnkid->ie_type = WLAN_EID_LINK_ID; lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - sizeof(struct ieee_types_header); @@ -683,8 +679,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, return ret; } if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, - extra_ies_len); + skb_put_data(skb, extra_ies, extra_ies_len); mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer, priv->cfg_bssid); break; @@ -697,8 +692,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, return ret; } if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, - extra_ies_len); + skb_put_data(skb, extra_ies, extra_ies_len); mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr, priv->cfg_bssid); break; @@ -747,7 +741,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap; - mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u)); + mgmt = skb_put(skb, offsetof(struct ieee80211_mgmt, u)); memset(mgmt, 0, 24); memcpy(mgmt->da, peer, ETH_ALEN); @@ -781,7 +775,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, return ret; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (void *)pos; @@ -856,8 +850,8 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, pkt_type = PKT_TYPE_MGMT; tx_control = 0; - pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); - memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); + pos = skb_put_zero(skb, + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); memcpy(pos, &pkt_type, sizeof(pkt_type)); memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control)); @@ -869,7 +863,7 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, } if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); + skb_put_data(skb, extra_ies, extra_ies_len); /* the TDLS link IE is always added last we are the responder */ diff --git a/drivers/net/wireless/marvell/mwifiex/txrx.c b/drivers/net/wireless/marvell/mwifiex/txrx.c index fac28bd8fbee..d848933466d9 100644 --- a/drivers/net/wireless/marvell/mwifiex/txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/txrx.c @@ -91,7 +91,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, struct mwifiex_sta_node *dest_node; struct ethhdr *hdr = (void *)skb->data; - hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; + hroom = adapter->intf_hdr_len; if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) { dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest); @@ -117,7 +117,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb, NULL); + skb, tx_param); } else { ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, @@ -179,18 +179,13 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter, mwifiex_write_data_complete(adapter, skb, 0, 0); return ret; } - if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { - if (adapter->iface_type == MWIFIEX_USB) - local_tx_pd = (struct txpd *)head_ptr; - else - local_tx_pd = (struct txpd *) (head_ptr + - INTF_HEADER_LEN); - } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + local_tx_pd = (struct txpd *)(head_ptr + adapter->intf_hdr_len); if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb, NULL); + skb, tx_param); } else { ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index 35d8636bdb91..477c29c9f5d9 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -160,7 +160,6 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, struct cfg80211_ap_settings *params) { const u8 *ht_ie; - u16 cap_info; if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) return; @@ -170,27 +169,6 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, if (ht_ie) { memcpy(&bss_cfg->ht_cap, ht_ie + 2, sizeof(struct ieee80211_ht_cap)); - cap_info = le16_to_cpu(bss_cfg->ht_cap.cap_info); - memset(&bss_cfg->ht_cap.mcs, 0, - priv->adapter->number_of_antenna); - switch (GET_RXSTBC(cap_info)) { - case MWIFIEX_RX_STBC1: - /* HT_CAP 1X1 mode */ - bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; - break; - case MWIFIEX_RX_STBC12: /* fall through */ - case MWIFIEX_RX_STBC123: - /* HT_CAP 2X2 mode */ - bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; - bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff; - break; - default: - mwifiex_dbg(priv->adapter, WARN, - "Unsupported RX-STBC, default to 2x2\n"); - bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; - bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff; - break; - } priv->ap_11n_enabled = 1; } else { memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap)); diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c index e10b2a52e78f..e8c8728db15a 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_event.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c @@ -312,6 +312,17 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) adapter->event_skb->len - sizeof(eventcause)); break; + + case EVENT_REMAIN_ON_CHAN_EXPIRED: + mwifiex_dbg(adapter, EVENT, + "event: uap: Remain on channel expired\n"); + cfg80211_remain_on_channel_expired(&priv->wdev, + priv->roc_cfg.cookie, + &priv->roc_cfg.chan, + GFP_ATOMIC); + memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg)); + break; + default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c index bf5660eb27d3..1e6a62c69ac5 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c @@ -468,8 +468,7 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); int pad; u16 pkt_type, pkt_offset; - int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : - INTF_HEADER_LEN; + int hroom = adapter->intf_hdr_len; if (!skb->len) { mwifiex_dbg(adapter, ERROR, @@ -521,7 +520,7 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, txpd->tx_pkt_offset = cpu_to_le16(pkt_offset); - /* make space for INTF_HEADER_LEN */ + /* make space for adapter->intf_hdr_len */ skb_push(skb, hroom); if (!txpd->tx_control) diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 2f7705c50161..cb1753e43ef4 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -363,6 +363,7 @@ static void mwifiex_usb_free(struct usb_card_rec *card) for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { port = &card->port[i]; for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { + usb_kill_urb(port->tx_data_list[j].urb); usb_free_urb(port->tx_data_list[j].urb); port->tx_data_list[j].urb = NULL; } @@ -424,7 +425,8 @@ static int mwifiex_usb_probe(struct usb_interface *intf, card->intf = intf; pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n", - udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, + le16_to_cpu(udev->descriptor.bcdUSB), + udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceProtocol); @@ -661,75 +663,6 @@ static struct usb_driver mwifiex_usb_driver = { .soft_unbind = 1, }; -static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) -{ - struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - struct usb_tx_data_port *port; - int i, j; - - card->tx_cmd.adapter = adapter; - card->tx_cmd.ep = card->tx_cmd_ep; - - card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->tx_cmd.urb) - return -ENOMEM; - - for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { - port = &card->port[i]; - if (!port->tx_data_ep) - continue; - port->tx_data_ix = 0; - if (port->tx_data_ep == MWIFIEX_USB_EP_DATA) - port->block_status = false; - else - port->block_status = true; - for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { - port->tx_data_list[j].adapter = adapter; - port->tx_data_list[j].ep = port->tx_data_ep; - port->tx_data_list[j].urb = - usb_alloc_urb(0, GFP_KERNEL); - if (!port->tx_data_list[j].urb) - return -ENOMEM; - } - } - - return 0; -} - -static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) -{ - struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - int i; - - card->rx_cmd.adapter = adapter; - card->rx_cmd.ep = card->rx_cmd_ep; - - card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->rx_cmd.urb) - return -ENOMEM; - - card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); - if (!card->rx_cmd.skb) - return -ENOMEM; - - if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) - return -1; - - for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { - card->rx_data_list[i].adapter = adapter; - card->rx_data_list[i].ep = card->rx_data_ep; - - card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->rx_data_list[i].urb) - return -1; - if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], - MWIFIEX_RX_DATA_BUF_SIZE)) - return -1; - } - - return 0; -} - static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, u32 *len, u8 ep, u32 timeout) { @@ -845,6 +778,364 @@ static inline u8 mwifiex_usb_data_sent(struct mwifiex_adapter *adapter) return true; } +static int mwifiex_usb_construct_send_urb(struct mwifiex_adapter *adapter, + struct usb_tx_data_port *port, u8 ep, + struct urb_context *context, + struct sk_buff *skb_send) +{ + struct usb_card_rec *card = adapter->card; + int ret = -EINPROGRESS; + struct urb *tx_urb; + + context->adapter = adapter; + context->ep = ep; + context->skb = skb_send; + tx_urb = context->urb; + + if (ep == card->tx_cmd_ep && + card->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT) + usb_fill_int_urb(tx_urb, card->udev, + usb_sndintpipe(card->udev, ep), skb_send->data, + skb_send->len, mwifiex_usb_tx_complete, + (void *)context, card->tx_cmd_interval); + else + usb_fill_bulk_urb(tx_urb, card->udev, + usb_sndbulkpipe(card->udev, ep), + skb_send->data, skb_send->len, + mwifiex_usb_tx_complete, (void *)context); + + tx_urb->transfer_flags |= URB_ZERO_PACKET; + + if (ep == card->tx_cmd_ep) + atomic_inc(&card->tx_cmd_urb_pending); + else + atomic_inc(&port->tx_data_urb_pending); + + if (ep != card->tx_cmd_ep && + atomic_read(&port->tx_data_urb_pending) == + MWIFIEX_TX_DATA_URB) { + port->block_status = true; + adapter->data_sent = mwifiex_usb_data_sent(adapter); + ret = -ENOSR; + } + + if (usb_submit_urb(tx_urb, GFP_ATOMIC)) { + mwifiex_dbg(adapter, ERROR, + "%s: usb_submit_urb failed\n", __func__); + if (ep == card->tx_cmd_ep) { + atomic_dec(&card->tx_cmd_urb_pending); + } else { + atomic_dec(&port->tx_data_urb_pending); + port->block_status = false; + adapter->data_sent = false; + if (port->tx_data_ix) + port->tx_data_ix--; + else + port->tx_data_ix = MWIFIEX_TX_DATA_URB; + } + ret = -1; + } + + return ret; +} + +static int mwifiex_usb_prepare_tx_aggr_skb(struct mwifiex_adapter *adapter, + struct usb_tx_data_port *port, + struct sk_buff **skb_send) +{ + struct sk_buff *skb_aggr, *skb_tmp; + u8 *payload, pad; + u16 align = adapter->bus_aggr.tx_aggr_align; + struct mwifiex_txinfo *tx_info = NULL; + bool is_txinfo_set = false; + + /* Packets in aggr_list will be send in either skb_aggr or + * write complete, delete the tx_aggr timer + */ + if (port->tx_aggr.timer_cnxt.is_hold_timer_set) { + del_timer(&port->tx_aggr.timer_cnxt.hold_timer); + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; + } + + skb_aggr = mwifiex_alloc_dma_align_buf(port->tx_aggr.aggr_len, + GFP_ATOMIC); + if (!skb_aggr) { + mwifiex_dbg(adapter, ERROR, + "%s: alloc skb_aggr failed\n", __func__); + + while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list))) + mwifiex_write_data_complete(adapter, skb_tmp, 0, -1); + + port->tx_aggr.aggr_num = 0; + port->tx_aggr.aggr_len = 0; + return -EBUSY; + } + + tx_info = MWIFIEX_SKB_TXCB(skb_aggr); + memset(tx_info, 0, sizeof(*tx_info)); + + while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list))) { + /* padding for aligning next packet header*/ + pad = (align - (skb_tmp->len & (align - 1))) % align; + payload = skb_put(skb_aggr, skb_tmp->len + pad); + memcpy(payload, skb_tmp->data, skb_tmp->len); + if (skb_queue_empty(&port->tx_aggr.aggr_list)) { + /* do not padding for last packet*/ + *(u16 *)payload = cpu_to_le16(skb_tmp->len); + *(u16 *)&payload[2] = + cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2 | 0x80); + skb_trim(skb_aggr, skb_aggr->len - pad); + } else { + /* add aggregation interface header */ + *(u16 *)payload = cpu_to_le16(skb_tmp->len + pad); + *(u16 *)&payload[2] = + cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2); + } + + if (!is_txinfo_set) { + tx_info->bss_num = MWIFIEX_SKB_TXCB(skb_tmp)->bss_num; + tx_info->bss_type = MWIFIEX_SKB_TXCB(skb_tmp)->bss_type; + is_txinfo_set = true; + } + + port->tx_aggr.aggr_num--; + port->tx_aggr.aggr_len -= (skb_tmp->len + pad); + mwifiex_write_data_complete(adapter, skb_tmp, 0, 0); + } + + tx_info->pkt_len = skb_aggr->len - + (sizeof(struct txpd) + adapter->intf_hdr_len); + tx_info->flags |= MWIFIEX_BUF_FLAG_AGGR_PKT; + + port->tx_aggr.aggr_num = 0; + port->tx_aggr.aggr_len = 0; + *skb_send = skb_aggr; + + return 0; +} + +/* This function prepare data packet to be send under usb tx aggregation + * protocol, check current usb aggregation status, link packet to aggrgation + * list if possible, work flow as below: + * (1) if only 1 packet available, add usb tx aggregation header and send. + * (2) if packet is able to aggregated, link it to current aggregation list. + * (3) if packet is not able to aggregated, aggregate and send exist packets + * in aggrgation list. Then, link packet in the list if there is more + * packet in transmit queue, otherwise try to transmit single packet. + */ +static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep, + struct sk_buff *skb, + struct mwifiex_tx_param *tx_param, + struct usb_tx_data_port *port) +{ + u8 *payload, pad; + u16 align = adapter->bus_aggr.tx_aggr_align; + struct sk_buff *skb_send = NULL; + struct urb_context *context = NULL; + struct txpd *local_tx_pd = + (struct txpd *)((u8 *)skb->data + adapter->intf_hdr_len); + u8 f_send_aggr_buf = 0; + u8 f_send_cur_buf = 0; + u8 f_precopy_cur_buf = 0; + u8 f_postcopy_cur_buf = 0; + u32 timeout; + int ret; + + /* padding to ensure each packet alginment */ + pad = (align - (skb->len & (align - 1))) % align; + + if (tx_param && tx_param->next_pkt_len) { + /* next packet available in tx queue*/ + if (port->tx_aggr.aggr_len + skb->len + pad > + adapter->bus_aggr.tx_aggr_max_size) { + f_send_aggr_buf = 1; + f_postcopy_cur_buf = 1; + } else { + /* current packet could be aggregated*/ + f_precopy_cur_buf = 1; + + if (port->tx_aggr.aggr_len + skb->len + pad + + tx_param->next_pkt_len > + adapter->bus_aggr.tx_aggr_max_size || + port->tx_aggr.aggr_num + 2 > + adapter->bus_aggr.tx_aggr_max_num) { + /* next packet could not be aggregated + * send current aggregation buffer + */ + f_send_aggr_buf = 1; + } + } + } else { + /* last packet in tx queue */ + if (port->tx_aggr.aggr_num > 0) { + /* pending packets in aggregation buffer*/ + if (port->tx_aggr.aggr_len + skb->len + pad > + adapter->bus_aggr.tx_aggr_max_size) { + /* current packet not be able to aggregated, + * send aggr buffer first, then send packet. + */ + f_send_cur_buf = 1; + } else { + /* last packet, Aggregation and send */ + f_precopy_cur_buf = 1; + } + + f_send_aggr_buf = 1; + } else { + /* no pending packets in aggregation buffer, + * send current packet immediately + */ + f_send_cur_buf = 1; + } + } + + if (local_tx_pd->flags & MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET) { + /* Send NULL packet immediately*/ + if (f_precopy_cur_buf) { + if (skb_queue_empty(&port->tx_aggr.aggr_list)) { + f_precopy_cur_buf = 0; + f_send_aggr_buf = 0; + f_send_cur_buf = 1; + } else { + f_send_aggr_buf = 1; + } + } else if (f_postcopy_cur_buf) { + f_send_cur_buf = 1; + f_postcopy_cur_buf = 0; + } + } + + if (f_precopy_cur_buf) { + skb_queue_tail(&port->tx_aggr.aggr_list, skb); + port->tx_aggr.aggr_len += (skb->len + pad); + port->tx_aggr.aggr_num++; + if (f_send_aggr_buf) + goto send_aggr_buf; + + /* packet will not been send immediately, + * set a timer to make sure it will be sent under + * strict time limit. Dynamically fit the timeout + * value, according to packets number in aggr_list + */ + if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) { + port->tx_aggr.timer_cnxt.hold_tmo_msecs = + MWIFIEX_USB_TX_AGGR_TMO_MIN; + timeout = + port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + port->tx_aggr.timer_cnxt.is_hold_timer_set = true; + } else { + if (port->tx_aggr.timer_cnxt.hold_tmo_msecs < + MWIFIEX_USB_TX_AGGR_TMO_MAX) { + /* Dyanmic fit timeout */ + timeout = + ++port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + } + } + } + +send_aggr_buf: + if (f_send_aggr_buf) { + ret = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send); + if (!ret) { + context = &port->tx_data_list[port->tx_data_ix++]; + ret = mwifiex_usb_construct_send_urb(adapter, port, ep, + context, skb_send); + if (ret == -1) + mwifiex_write_data_complete(adapter, skb_send, + 0, -1); + } + } + + if (f_send_cur_buf) { + if (f_send_aggr_buf) { + if (atomic_read(&port->tx_data_urb_pending) >= + MWIFIEX_TX_DATA_URB) { + port->block_status = true; + adapter->data_sent = + mwifiex_usb_data_sent(adapter); + /* no available urb, postcopy packet*/ + f_postcopy_cur_buf = 1; + goto postcopy_cur_buf; + } + + if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) + port->tx_data_ix = 0; + } + + payload = skb->data; + *(u16 *)&payload[2] = + cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2 | 0x80); + *(u16 *)payload = cpu_to_le16(skb->len); + skb_send = skb; + context = &port->tx_data_list[port->tx_data_ix++]; + return mwifiex_usb_construct_send_urb(adapter, port, ep, + context, skb_send); + } + +postcopy_cur_buf: + if (f_postcopy_cur_buf) { + skb_queue_tail(&port->tx_aggr.aggr_list, skb); + port->tx_aggr.aggr_len += (skb->len + pad); + port->tx_aggr.aggr_num++; + /* New aggregation begin, start timer */ + if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) { + port->tx_aggr.timer_cnxt.hold_tmo_msecs = + MWIFIEX_USB_TX_AGGR_TMO_MIN; + timeout = port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + port->tx_aggr.timer_cnxt.is_hold_timer_set = true; + } + } + + return -EINPROGRESS; +} + +static void mwifiex_usb_tx_aggr_tmo(unsigned long context) +{ + struct urb_context *urb_cnxt = NULL; + struct sk_buff *skb_send = NULL; + struct tx_aggr_tmr_cnxt *timer_context = + (struct tx_aggr_tmr_cnxt *)context; + struct mwifiex_adapter *adapter = timer_context->adapter; + struct usb_tx_data_port *port = timer_context->port; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&port->tx_aggr_lock, flags); + err = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send); + if (err) { + mwifiex_dbg(adapter, ERROR, + "prepare tx aggr skb failed, err=%d\n", err); + return; + } + + if (atomic_read(&port->tx_data_urb_pending) >= + MWIFIEX_TX_DATA_URB) { + port->block_status = true; + adapter->data_sent = + mwifiex_usb_data_sent(adapter); + err = -1; + goto done; + } + + if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) + port->tx_data_ix = 0; + + urb_cnxt = &port->tx_data_list[port->tx_data_ix++]; + err = mwifiex_usb_construct_send_urb(adapter, port, port->tx_data_ep, + urb_cnxt, skb_send); +done: + if (err == -1) + mwifiex_write_data_complete(adapter, skb_send, 0, -1); + spin_unlock_irqrestore(&port->tx_aggr_lock, flags); +} + /* This function write a command/data packet to card. */ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, struct sk_buff *skb, @@ -853,9 +1144,8 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, struct usb_card_rec *card = adapter->card; struct urb_context *context = NULL; struct usb_tx_data_port *port = NULL; - u8 *data = (u8 *)skb->data; - struct urb *tx_urb; - int idx, ret = -EINPROGRESS; + unsigned long flags; + int idx, ret; if (adapter->is_suspended) { mwifiex_dbg(adapter, ERROR, @@ -873,6 +1163,7 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, if (ep == card->tx_cmd_ep) { context = &card->tx_cmd; } else { + /* get the data port structure for endpoint */ for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { if (ep == card->port[idx].tx_data_ep) { port = &card->port[idx]; @@ -885,67 +1176,105 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, } if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) port->tx_data_ix = 0; - context = - &port->tx_data_list[port->tx_data_ix++]; break; } } + if (!port) { mwifiex_dbg(adapter, ERROR, "Wrong usb tx data port\n"); return -1; } - } - context->adapter = adapter; - context->ep = ep; - context->skb = skb; - tx_urb = context->urb; + if (adapter->bus_aggr.enable) { + spin_lock_irqsave(&port->tx_aggr_lock, flags); + ret = mwifiex_usb_aggr_tx_data(adapter, ep, skb, + tx_param, port); + spin_unlock_irqrestore(&port->tx_aggr_lock, flags); + return ret; + } - if (ep == card->tx_cmd_ep && - card->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT) - usb_fill_int_urb(tx_urb, card->udev, - usb_sndintpipe(card->udev, ep), data, - skb->len, mwifiex_usb_tx_complete, - (void *)context, card->tx_cmd_interval); - else - usb_fill_bulk_urb(tx_urb, card->udev, - usb_sndbulkpipe(card->udev, ep), data, - skb->len, mwifiex_usb_tx_complete, - (void *)context); + context = &port->tx_data_list[port->tx_data_ix++]; + } - tx_urb->transfer_flags |= URB_ZERO_PACKET; + return mwifiex_usb_construct_send_urb(adapter, port, ep, context, skb); +} - if (ep == card->tx_cmd_ep) - atomic_inc(&card->tx_cmd_urb_pending); - else - atomic_inc(&port->tx_data_urb_pending); +static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + struct usb_tx_data_port *port; + int i, j; - if (ep != card->tx_cmd_ep && - atomic_read(&port->tx_data_urb_pending) == - MWIFIEX_TX_DATA_URB) { - port->block_status = true; - adapter->data_sent = mwifiex_usb_data_sent(adapter); - ret = -ENOSR; - } + card->tx_cmd.adapter = adapter; + card->tx_cmd.ep = card->tx_cmd_ep; - if (usb_submit_urb(tx_urb, GFP_ATOMIC)) { - mwifiex_dbg(adapter, ERROR, - "%s: usb_submit_urb failed\n", __func__); - if (ep == card->tx_cmd_ep) { - atomic_dec(&card->tx_cmd_urb_pending); - } else { - atomic_dec(&port->tx_data_urb_pending); + card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->tx_cmd.urb) + return -ENOMEM; + + for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { + port = &card->port[i]; + if (!port->tx_data_ep) + continue; + port->tx_data_ix = 0; + skb_queue_head_init(&port->tx_aggr.aggr_list); + if (port->tx_data_ep == MWIFIEX_USB_EP_DATA) port->block_status = false; - adapter->data_sent = false; - if (port->tx_data_ix) - port->tx_data_ix--; - else - port->tx_data_ix = MWIFIEX_TX_DATA_URB; + else + port->block_status = true; + for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { + port->tx_data_list[j].adapter = adapter; + port->tx_data_list[j].ep = port->tx_data_ep; + port->tx_data_list[j].urb = + usb_alloc_urb(0, GFP_KERNEL); + if (!port->tx_data_list[j].urb) + return -ENOMEM; } - ret = -1; + + port->tx_aggr.timer_cnxt.adapter = adapter; + port->tx_aggr.timer_cnxt.port = port; + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; + setup_timer(&port->tx_aggr.timer_cnxt.hold_timer, + mwifiex_usb_tx_aggr_tmo, + (unsigned long)&port->tx_aggr.timer_cnxt); } - return ret; + return 0; +} + +static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + int i; + + card->rx_cmd.adapter = adapter; + card->rx_cmd.ep = card->rx_cmd_ep; + + card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_cmd.urb) + return -ENOMEM; + + card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); + if (!card->rx_cmd.skb) + return -ENOMEM; + + if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) + return -1; + + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { + card->rx_data_list[i].adapter = adapter; + card->rx_data_list[i].ep = card->rx_data_ep; + + card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_data_list[i].urb) + return -1; + if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], + MWIFIEX_RX_DATA_BUF_SIZE)) + return -1; + } + + return 0; } /* This function register usb device and initialize parameter. */ @@ -988,10 +1317,32 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) return 0; } +static void mwifiex_usb_cleanup_tx_aggr(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + struct usb_tx_data_port *port; + struct sk_buff *skb_tmp; + int idx; + + for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { + port = &card->port[idx]; + if (adapter->bus_aggr.enable) + while ((skb_tmp = + skb_dequeue(&port->tx_aggr.aggr_list))) + mwifiex_write_data_complete(adapter, skb_tmp, + 0, -1); + del_timer_sync(&port->tx_aggr.timer_cnxt.hold_timer); + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; + } +} + static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + mwifiex_usb_cleanup_tx_aggr(adapter); + card->adapter = NULL; } diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h index e36bd63172ff..37abd228a84f 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.h +++ b/drivers/net/wireless/marvell/mwifiex/usb.h @@ -64,12 +64,35 @@ struct urb_context { u8 ep; }; +#define MWIFIEX_USB_TX_AGGR_TMO_MIN 1 +#define MWIFIEX_USB_TX_AGGR_TMO_MAX 4 + +struct tx_aggr_tmr_cnxt { + struct mwifiex_adapter *adapter; + struct usb_tx_data_port *port; + struct timer_list hold_timer; + bool is_hold_timer_set; + u32 hold_tmo_msecs; +}; + +struct usb_tx_aggr { + struct sk_buff_head aggr_list; + int aggr_len; + int aggr_num; + struct tx_aggr_tmr_cnxt timer_cnxt; +}; + struct usb_tx_data_port { u8 tx_data_ep; u8 block_status; atomic_t tx_data_urb_pending; int tx_data_ix; struct urb_context tx_data_list[MWIFIEX_TX_DATA_URB]; + /* usb tx aggregation*/ + struct usb_tx_aggr tx_aggr; + struct sk_buff *skb_aggr[MWIFIEX_TX_DATA_URB]; + /* lock for protect tx aggregation data path*/ + spinlock_t tx_aggr_lock; }; struct usb_card_rec { diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index e4ff3b973850..0edd26881321 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -868,12 +868,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, return; default: list_head = priv->wmm.tid_tbl_ptr[tid_down].ra_list; - if (!list_empty(&list_head)) - ra_list = list_first_entry( - &list_head, struct mwifiex_ra_list_tbl, - list); - else - ra_list = NULL; + ra_list = list_first_entry_or_null(&list_head, + struct mwifiex_ra_list_tbl, list); break; } } else { @@ -1363,13 +1359,13 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + tx_param.next_pkt_len = + ((skb_next) ? skb_next->len + + sizeof(struct txpd) : 0); if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb, NULL); + skb, &tx_param); } else { - tx_param.next_pkt_len = - ((skb_next) ? skb_next->len + - sizeof(struct txpd) : 0); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, &tx_param); } diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index a8bc064bc14f..660267b359e4 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -52,7 +52,7 @@ mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, goto bad_frame; if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) { - memcpy(skb_put(skb, hdr_len), data, hdr_len); + skb_put_data(skb, data, hdr_len); data += hdr_len + 2; true_len -= hdr_len; @@ -63,7 +63,7 @@ mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8; frag = true_len - copy; - memcpy(skb_put(skb, copy), data, copy); + skb_put_data(skb, data, copy); data += copy; if (frag) { diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index a9f5f398b2f8..65a8004418ea 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -68,7 +68,7 @@ mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len) skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL); if (skb) { skb_reserve(skb, MT_DMA_HDR_LEN); - memcpy(skb_put(skb, len), data, len); + skb_put_data(skb, data, len); } return skb; diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c index ad77bec1ba0f..3600e911a63e 100644 --- a/drivers/net/wireless/mediatek/mt7601u/tx.c +++ b/drivers/net/wireless/mediatek/mt7601u/tx.c @@ -148,7 +148,7 @@ mt7601u_push_txwi(struct mt7601u_dev *dev, struct sk_buff *skb, u16 rate_ctl; u8 nss; - txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi)); + txwi = skb_push(skb, sizeof(struct mt76_txwi)); memset(txwi, 0, sizeof(*txwi)); if (!wcid->tx_rate_set) diff --git a/drivers/net/wireless/quantenna/Kconfig b/drivers/net/wireless/quantenna/Kconfig new file mode 100644 index 000000000000..30943656e989 --- /dev/null +++ b/drivers/net/wireless/quantenna/Kconfig @@ -0,0 +1,16 @@ +config WLAN_VENDOR_QUANTENNA + bool "Quantenna wireless cards support" + default y + ---help--- + If you have a wireless card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about cards. If you say Y, you will be asked for + your specific card in the following questions. + +if WLAN_VENDOR_QUANTENNA + +source "drivers/net/wireless/quantenna/qtnfmac/Kconfig" + +endif # WLAN_VENDOR_QUANTENNA diff --git a/drivers/net/wireless/quantenna/Makefile b/drivers/net/wireless/quantenna/Makefile new file mode 100644 index 000000000000..baebfbde119e --- /dev/null +++ b/drivers/net/wireless/quantenna/Makefile @@ -0,0 +1,6 @@ +# +# Copyright (c) 2015-2016 Quantenna Communications, Inc. +# All rights reserved. +# + +obj-$(CONFIG_QTNFMAC) += qtnfmac/ diff --git a/drivers/net/wireless/quantenna/qtnfmac/Kconfig b/drivers/net/wireless/quantenna/qtnfmac/Kconfig new file mode 100644 index 000000000000..025fa6018550 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/Kconfig @@ -0,0 +1,19 @@ +config QTNFMAC + tristate + depends on QTNFMAC_PEARL_PCIE + default m if QTNFMAC_PEARL_PCIE=m + default y if QTNFMAC_PEARL_PCIE=y + +config QTNFMAC_PEARL_PCIE + tristate "Quantenna QSR10g PCIe support" + default n + depends on HAS_DMA && PCI && CFG80211 + select QTNFMAC + select FW_LOADER + select CRC32 + ---help--- + This option adds support for wireless adapters based on Quantenna + 802.11ac QSR10g (aka Pearl) FullMAC chipset running over PCIe. + + If you choose to build it as a module, two modules will be built: + qtnfmac.ko and qtnfmac_pearl_pcie.ko. diff --git a/drivers/net/wireless/quantenna/qtnfmac/Makefile b/drivers/net/wireless/quantenna/qtnfmac/Makefile new file mode 100644 index 000000000000..0d618e5e5f5b --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (c) 2015-2016 Quantenna Communications, Inc. +# All rights reserved. +# + +ccflags-y += \ + -Idrivers/net/wireless/quantenna/qtnfmac + +obj-$(CONFIG_QTNFMAC) += qtnfmac.o +qtnfmac-objs += \ + core.o \ + commands.o \ + trans.o \ + cfg80211.o \ + event.o \ + util.o \ + qlink_util.o + +# + +obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o + +qtnfmac_pearl_pcie-objs += \ + shm_ipc.o \ + pearl/pcie.o + +qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o + +# + +ccflags-y += -D__CHECK_ENDIAN diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h new file mode 100644 index 000000000000..dda05003d522 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015 Quantenna Communications + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QTNFMAC_BUS_H +#define QTNFMAC_BUS_H + +#include <linux/netdevice.h> +#include <linux/workqueue.h> + +#define QTNF_MAX_MAC 3 + +enum qtnf_fw_state { + QTNF_FW_STATE_RESET, + QTNF_FW_STATE_FW_DNLD_DONE, + QTNF_FW_STATE_BOOT_DONE, + QTNF_FW_STATE_ACTIVE, + QTNF_FW_STATE_DEAD, +}; + +struct qtnf_bus; + +struct qtnf_bus_ops { + /* mgmt methods */ + int (*preinit)(struct qtnf_bus *); + void (*stop)(struct qtnf_bus *); + + /* control path methods */ + int (*control_tx)(struct qtnf_bus *, struct sk_buff *); + + /* data xfer methods */ + int (*data_tx)(struct qtnf_bus *, struct sk_buff *); + void (*data_tx_timeout)(struct qtnf_bus *, struct net_device *); + void (*data_rx_start)(struct qtnf_bus *); + void (*data_rx_stop)(struct qtnf_bus *); +}; + +struct qtnf_bus { + struct device *dev; + enum qtnf_fw_state fw_state; + u32 chip; + u32 chiprev; + const struct qtnf_bus_ops *bus_ops; + struct qtnf_wmac *mac[QTNF_MAX_MAC]; + struct qtnf_qlink_transport trans; + struct qtnf_hw_info hw_info; + char fwname[32]; + struct napi_struct mux_napi; + struct net_device mux_dev; + struct completion request_firmware_complete; + struct workqueue_struct *workqueue; + struct work_struct event_work; + struct mutex bus_lock; /* lock during command/event processing */ + struct dentry *dbg_dir; + /* bus private data */ + char bus_priv[0] __aligned(sizeof(void *)); +}; + +static inline void *get_bus_priv(struct qtnf_bus *bus) +{ + if (WARN(!bus, "qtnfmac: invalid bus pointer")) + return NULL; + + return &bus->bus_priv; +} + +/* callback wrappers */ + +static inline int qtnf_bus_preinit(struct qtnf_bus *bus) +{ + if (!bus->bus_ops->preinit) + return 0; + return bus->bus_ops->preinit(bus); +} + +static inline void qtnf_bus_stop(struct qtnf_bus *bus) +{ + if (!bus->bus_ops->stop) + return; + bus->bus_ops->stop(bus); +} + +static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + return bus->bus_ops->data_tx(bus, skb); +} + +static inline void +qtnf_bus_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) +{ + return bus->bus_ops->data_tx_timeout(bus, ndev); +} + +static inline int qtnf_bus_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + return bus->bus_ops->control_tx(bus, skb); +} + +static inline void qtnf_bus_data_rx_start(struct qtnf_bus *bus) +{ + return bus->bus_ops->data_rx_start(bus); +} + +static inline void qtnf_bus_data_rx_stop(struct qtnf_bus *bus) +{ + return bus->bus_ops->data_rx_stop(bus); +} + +static __always_inline void qtnf_bus_lock(struct qtnf_bus *bus) +{ + mutex_lock(&bus->bus_lock); +} + +static __always_inline void qtnf_bus_unlock(struct qtnf_bus *bus) +{ + mutex_unlock(&bus->bus_lock); +} + +/* interface functions from common layer */ + +void qtnf_rx_frame(struct device *dev, struct sk_buff *rxp); +int qtnf_core_attach(struct qtnf_bus *bus); +void qtnf_core_detach(struct qtnf_bus *bus); +void qtnf_txflowblock(struct device *dev, bool state); +void qtnf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); + +#endif /* QTNFMAC_BUS_H */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c new file mode 100644 index 000000000000..e3c090008125 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -0,0 +1,995 @@ +/* + * Copyright (c) 2012-2012 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/etherdevice.h> +#include <linux/vmalloc.h> +#include <linux/ieee80211.h> +#include <net/cfg80211.h> +#include <net/netlink.h> + +#include "cfg80211.h" +#include "commands.h" +#include "core.h" +#include "util.h" +#include "bus.h" + +/* Supported rates to be advertised to the cfg80211 */ +static struct ieee80211_rate qtnf_rates_2g[] = { + {.bitrate = 10, .hw_value = 2, }, + {.bitrate = 20, .hw_value = 4, }, + {.bitrate = 55, .hw_value = 11, }, + {.bitrate = 110, .hw_value = 22, }, + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, +}; + +/* Supported rates to be advertised to the cfg80211 */ +static struct ieee80211_rate qtnf_rates_5g[] = { + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, +}; + +/* Supported crypto cipher suits to be advertised to cfg80211 */ +static const u32 qtnf_cipher_suites[] = { + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +/* Supported mgmt frame types to be advertised to cfg80211 */ +static const struct ieee80211_txrx_stypes +qtnf_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_AP] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, +}; + +static int +qtnf_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + u8 *mac_addr; + int ret; + + if (params) + mac_addr = params->macaddr; + else + mac_addr = NULL; + + qtnf_scan_done(vif->mac, true); + + ret = qtnf_cmd_send_change_intf_type(vif, type, mac_addr); + if (ret) { + pr_err("VIF%u.%u: failed to change VIF type: %d\n", + vif->mac->macid, vif->vifid, ret); + return ret; + } + + vif->wdev.iftype = type; + return 0; +} + +int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct net_device *netdev = wdev->netdev; + struct qtnf_vif *vif; + + if (WARN_ON(!netdev)) + return -EFAULT; + + vif = qtnf_netdev_get_priv(wdev->netdev); + + if (qtnf_cmd_send_del_intf(vif)) + pr_err("VIF%u.%u: failed to delete VIF\n", vif->mac->macid, + vif->vifid); + + /* Stop data */ + netif_tx_stop_all_queues(netdev); + if (netif_carrier_ok(netdev)) + netif_carrier_off(netdev); + + if (netdev->reg_state == NETREG_REGISTERED) + unregister_netdevice(netdev); + + vif->netdev->ieee80211_ptr = NULL; + vif->netdev = NULL; + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + eth_zero_addr(vif->mac_addr); + + return 0; +} + +static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_t, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct qtnf_wmac *mac; + struct qtnf_vif *vif; + u8 *mac_addr = NULL; + + mac = wiphy_priv(wiphy); + + if (!mac) + return ERR_PTR(-EFAULT); + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP: + vif = qtnf_mac_get_free_vif(mac); + if (!vif) { + pr_err("MAC%u: no free VIF available\n", mac->macid); + return ERR_PTR(-EFAULT); + } + + eth_zero_addr(vif->mac_addr); + vif->bss_priority = QTNF_DEF_BSS_PRIORITY; + vif->wdev.wiphy = wiphy; + vif->wdev.iftype = type; + vif->sta_state = QTNF_STA_DISCONNECTED; + break; + default: + pr_err("MAC%u: unsupported IF type %d\n", mac->macid, type); + return ERR_PTR(-ENOTSUPP); + } + + if (params) + mac_addr = params->macaddr; + + if (qtnf_cmd_send_add_intf(vif, type, mac_addr)) { + pr_err("VIF%u.%u: failed to add VIF\n", mac->macid, vif->vifid); + goto err_cmd; + } + + if (!is_valid_ether_addr(vif->mac_addr)) { + pr_err("VIF%u.%u: FW reported bad MAC: %pM\n", + mac->macid, vif->vifid, vif->mac_addr); + goto err_mac; + } + + if (qtnf_core_net_attach(mac, vif, name, name_assign_t, type)) { + pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid, + vif->vifid); + goto err_net; + } + + vif->wdev.netdev = vif->netdev; + return &vif->wdev; + +err_net: + vif->netdev = NULL; +err_mac: + qtnf_cmd_send_del_intf(vif); +err_cmd: + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + + return ERR_PTR(-EFAULT); +} + +static int qtnf_mgmt_set_appie(struct qtnf_vif *vif, + const struct cfg80211_beacon_data *info) +{ + int ret = 0; + + if (!info->beacon_ies || !info->beacon_ies_len) { + ret = qtnf_cmd_send_mgmt_set_appie(vif, QLINK_MGMT_FRAME_BEACON, + NULL, 0); + } else { + ret = qtnf_cmd_send_mgmt_set_appie(vif, QLINK_MGMT_FRAME_BEACON, + info->beacon_ies, + info->beacon_ies_len); + } + + if (ret) + goto out; + + if (!info->proberesp_ies || !info->proberesp_ies_len) { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_PROBE_RESP, + NULL, 0); + } else { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_PROBE_RESP, + info->proberesp_ies, + info->proberesp_ies_len); + } + + if (ret) + goto out; + + if (!info->assocresp_ies || !info->assocresp_ies_len) { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_ASSOC_RESP, + NULL, 0); + } else { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_ASSOC_RESP, + info->assocresp_ies, + info->assocresp_ies_len); + } + +out: + return ret; +} + +static int qtnf_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *info) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: not started\n", vif->mac->macid, vif->vifid); + return -EFAULT; + } + + return qtnf_mgmt_set_appie(vif, info); +} + +static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + struct qtnf_bss_config *bss_cfg; + int ret; + + bss_cfg = &vif->bss_cfg; + + memset(bss_cfg, 0, sizeof(*bss_cfg)); + + bss_cfg->bcn_period = settings->beacon_interval; + bss_cfg->dtim = settings->dtim_period; + bss_cfg->auth_type = settings->auth_type; + bss_cfg->privacy = settings->privacy; + + bss_cfg->ssid_len = settings->ssid_len; + memcpy(&bss_cfg->ssid, settings->ssid, bss_cfg->ssid_len); + + memcpy(&bss_cfg->chandef, &settings->chandef, + sizeof(struct cfg80211_chan_def)); + memcpy(&bss_cfg->crypto, &settings->crypto, + sizeof(struct cfg80211_crypto_settings)); + + ret = qtnf_cmd_send_config_ap(vif); + if (ret) { + pr_err("VIF%u.%u: failed to push config to FW\n", + vif->mac->macid, vif->vifid); + goto out; + } + + if (!(vif->bss_status & QTNF_STATE_AP_CONFIG)) { + pr_err("VIF%u.%u: AP config failed in FW\n", vif->mac->macid, + vif->vifid); + ret = -EFAULT; + goto out; + } + + ret = qtnf_mgmt_set_appie(vif, &settings->beacon); + if (ret) { + pr_err("VIF%u.%u: failed to add IEs to beacon\n", + vif->mac->macid, vif->vifid); + goto out; + } + + ret = qtnf_cmd_send_start_ap(vif); + if (ret) { + pr_err("VIF%u.%u: failed to start AP\n", vif->mac->macid, + vif->vifid); + goto out; + } + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: FW failed to start AP operation\n", + vif->mac->macid, vif->vifid); + ret = -EFAULT; + } + +out: + return ret; +} + +static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_stop_ap(vif); + if (ret) { + pr_err("VIF%u.%u: failed to stop AP operation in FW\n", + vif->mac->macid, vif->vifid); + vif->bss_status &= ~QTNF_STATE_AP_START; + vif->bss_status &= ~QTNF_STATE_AP_CONFIG; + + netif_carrier_off(vif->netdev); + } + + return ret; +} + +static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_vif *vif; + int ret; + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + return -EFAULT; + } + + if (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT)) { + pr_err("MAC%u: can't modify retry params\n", mac->macid); + return -EOPNOTSUPP; + } + + ret = qtnf_cmd_send_update_phy_params(mac, changed); + if (ret) + pr_err("MAC%u: failed to update PHY params\n", mac->macid); + + return ret; +} + +static void +qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, + u16 frame_type, bool reg) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); + u16 mgmt_type; + u16 new_mask; + u16 qlink_frame_type = 0; + + mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; + + if (reg) + new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type); + else + new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type); + + if (new_mask == vif->mgmt_frames_bitmask) + return; + + switch (frame_type & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_REQ: + qlink_frame_type = QLINK_MGMT_FRAME_PROBE_REQ; + break; + case IEEE80211_STYPE_ACTION: + qlink_frame_type = QLINK_MGMT_FRAME_ACTION; + break; + default: + pr_warn("VIF%u.%u: unsupported frame type: %X\n", + vif->mac->macid, vif->vifid, + (frame_type & IEEE80211_FCTL_STYPE) >> 4); + return; + } + + if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) { + pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n", + vif->mac->macid, vif->vifid, reg ? "" : "un", + frame_type); + return; + } + + vif->mgmt_frames_bitmask = new_mask; + pr_debug("VIF%u.%u: %sregistered mgmt frame type 0x%x\n", + vif->mac->macid, vif->vifid, reg ? "" : "un", frame_type); +} + +static int +qtnf_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); + const struct ieee80211_mgmt *mgmt_frame = (void *)params->buf; + u32 short_cookie = prandom_u32(); + u16 flags = 0; + + *cookie = short_cookie; + + if (params->offchan) + flags |= QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN; + + if (params->no_cck) + flags |= QLINK_MGMT_FRAME_TX_FLAG_NO_CCK; + + if (params->dont_wait_for_ack) + flags |= QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT; + + pr_debug("%s freq:%u; FC:%.4X; DA:%pM; len:%zu; C:%.8X; FL:%.4X\n", + wdev->netdev->name, params->chan->center_freq, + le16_to_cpu(mgmt_frame->frame_control), mgmt_frame->da, + params->len, short_cookie, flags); + + return qtnf_cmd_send_mgmt_frame(vif, short_cookie, flags, + params->chan->center_freq, + params->buf, params->len); +} + +static int +qtnf_get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + + return qtnf_cmd_get_sta_info(vif, mac, sinfo); +} + +static int +qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + const struct qtnf_sta_node *sta_node; + int ret; + + sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx); + + if (unlikely(!sta_node)) + return -ENOENT; + + ether_addr_copy(mac, sta_node->mac_addr); + + ret = qtnf_cmd_get_sta_info(vif, sta_node->mac_addr, sinfo); + + if (unlikely(ret == -ENOENT)) { + qtnf_sta_list_del(&vif->sta_list, mac); + cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL); + sinfo->filled = 0; + } + + return ret; +} + +static int qtnf_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_add_key(vif, key_index, pairwise, mac_addr, params); + if (ret) + pr_err("VIF%u.%u: failed to add key: cipher=%x idx=%u pw=%u\n", + vif->mac->macid, vif->vifid, params->cipher, key_index, + pairwise); + + return ret; +} + +static int qtnf_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr); + if (ret) + pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n", + vif->mac->macid, vif->vifid, key_index, pairwise); + + return ret; +} + +static int qtnf_set_default_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool unicast, bool multicast) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_set_default_key(vif, key_index, unicast, multicast); + if (ret) + pr_err("VIF%u.%u: failed to set dflt key: idx=%u uc=%u mc=%u\n", + vif->mac->macid, vif->vifid, key_index, unicast, + multicast); + + return ret; +} + +static int +qtnf_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_set_default_mgmt_key(vif, key_index); + if (ret) + pr_err("VIF%u.%u: failed to set default MGMT key: idx=%u\n", + vif->mac->macid, vif->vifid, key_index); + + return ret; +} + +static int +qtnf_change_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_change_sta(vif, mac, params); + if (ret) + pr_err("VIF%u.%u: failed to change STA %pM\n", + vif->mac->macid, vif->vifid, mac); + + return ret; +} + +static int +qtnf_del_station(struct wiphy *wiphy, struct net_device *dev, + struct station_del_parameters *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + if (params->mac && + (vif->wdev.iftype == NL80211_IFTYPE_AP) && + !is_broadcast_ether_addr(params->mac) && + !qtnf_sta_list_lookup(&vif->sta_list, params->mac)) + return 0; + + qtnf_scan_done(vif->mac, true); + + ret = qtnf_cmd_send_del_sta(vif, params); + if (ret) + pr_err("VIF%u.%u: failed to delete STA %pM\n", + vif->mac->macid, vif->vifid, params->mac); + return ret; +} + +static int +qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + int ret; + + mac->scan_req = request; + + ret = qtnf_cmd_send_scan(mac); + if (ret) + pr_err("MAC%u: failed to start scan\n", mac->macid); + + return ret; +} + +static int +qtnf_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + struct qtnf_bss_config *bss_cfg; + int ret; + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (vif->sta_state != QTNF_STA_DISCONNECTED) + return -EBUSY; + + bss_cfg = &vif->bss_cfg; + memset(bss_cfg, 0, sizeof(*bss_cfg)); + + bss_cfg->ssid_len = sme->ssid_len; + memcpy(&bss_cfg->ssid, sme->ssid, bss_cfg->ssid_len); + bss_cfg->chandef.chan = sme->channel; + bss_cfg->auth_type = sme->auth_type; + bss_cfg->privacy = sme->privacy; + bss_cfg->mfp = sme->mfp; + + if ((sme->bg_scan_period > 0) && + (sme->bg_scan_period <= QTNF_MAX_BG_SCAN_PERIOD)) + bss_cfg->bg_scan_period = sme->bg_scan_period; + else if (sme->bg_scan_period == -1) + bss_cfg->bg_scan_period = QTNF_DEFAULT_BG_SCAN_PERIOD; + else + bss_cfg->bg_scan_period = 0; /* disabled */ + + bss_cfg->connect_flags = 0; + + if (sme->flags & ASSOC_REQ_DISABLE_HT) + bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_HT; + if (sme->flags & ASSOC_REQ_DISABLE_VHT) + bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_VHT; + if (sme->flags & ASSOC_REQ_USE_RRM) + bss_cfg->connect_flags |= QLINK_STA_CONNECT_USE_RRM; + + memcpy(&bss_cfg->crypto, &sme->crypto, sizeof(bss_cfg->crypto)); + if (sme->bssid) + ether_addr_copy(bss_cfg->bssid, sme->bssid); + else + eth_zero_addr(bss_cfg->bssid); + + ret = qtnf_cmd_send_connect(vif, sme); + if (ret) { + pr_err("VIF%u.%u: failed to connect\n", vif->mac->macid, + vif->vifid); + return ret; + } + + vif->sta_state = QTNF_STA_CONNECTING; + return 0; +} + +static int +qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_vif *vif; + int ret; + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + return -EFAULT; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (vif->sta_state == QTNF_STA_DISCONNECTED) + return 0; + + ret = qtnf_cmd_send_disconnect(vif, reason_code); + if (ret) { + pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, + vif->vifid); + return ret; + } + + vif->sta_state = QTNF_STA_DISCONNECTED; + return 0; +} + +static struct cfg80211_ops qtn_cfg80211_ops = { + .add_virtual_intf = qtnf_add_virtual_intf, + .change_virtual_intf = qtnf_change_virtual_intf, + .del_virtual_intf = qtnf_del_virtual_intf, + .start_ap = qtnf_start_ap, + .change_beacon = qtnf_change_beacon, + .stop_ap = qtnf_stop_ap, + .set_wiphy_params = qtnf_set_wiphy_params, + .mgmt_frame_register = qtnf_mgmt_frame_register, + .mgmt_tx = qtnf_mgmt_tx, + .change_station = qtnf_change_station, + .del_station = qtnf_del_station, + .get_station = qtnf_get_station, + .dump_station = qtnf_dump_station, + .add_key = qtnf_add_key, + .del_key = qtnf_del_key, + .set_default_key = qtnf_set_default_key, + .set_default_mgmt_key = qtnf_set_default_mgmt_key, + .scan = qtnf_scan, + .connect = qtnf_connect, + .disconnect = qtnf_disconnect +}; + +static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *req) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_bus *bus; + struct qtnf_vif *vif; + struct qtnf_wmac *chan_mac; + int i; + enum nl80211_band band; + + bus = mac->bus; + + pr_debug("MAC%u: initiator=%d alpha=%c%c\n", mac->macid, req->initiator, + req->alpha2[0], req->alpha2[1]); + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + return; + } + + /* ignore non-ISO3166 country codes */ + for (i = 0; i < sizeof(req->alpha2); i++) { + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { + pr_err("MAC%u: not an ISO3166 code\n", mac->macid); + return; + } + } + if (!strncasecmp(req->alpha2, bus->hw_info.alpha2_code, + sizeof(req->alpha2))) { + pr_warn("MAC%u: unchanged country code\n", mac->macid); + return; + } + + if (qtnf_cmd_send_regulatory_config(mac, req->alpha2)) { + pr_err("MAC%u: failed to configure regulatory\n", mac->macid); + return; + } + + for (i = 0; i < bus->hw_info.num_mac; i++) { + chan_mac = bus->mac[i]; + + if (!chan_mac) + continue; + + if (!(bus->hw_info.mac_bitmap & BIT(i))) + continue; + + for (band = 0; band < NUM_NL80211_BANDS; ++band) { + if (!wiphy->bands[band]) + continue; + + if (qtnf_cmd_get_mac_chan_info(chan_mac, + wiphy->bands[band])) { + pr_err("MAC%u: can't get channel info\n", + chan_mac->macid); + qtnf_core_detach(bus); + + return; + } + } + } +} + +void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo, + struct ieee80211_supported_band *band) +{ + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + + ht_cap = &band->ht_cap; + ht_cap->ht_supported = true; + memcpy(&ht_cap->cap, &macinfo->ht_cap.cap_info, + sizeof(u16)); + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + memcpy(&ht_cap->mcs, &macinfo->ht_cap.mcs, + sizeof(ht_cap->mcs)); + + if (macinfo->phymode_cap & QLINK_PHYMODE_AC) { + vht_cap = &band->vht_cap; + vht_cap->vht_supported = true; + memcpy(&vht_cap->cap, + &macinfo->vht_cap.vht_cap_info, sizeof(u32)); + /* Update MCS support for VHT */ + memcpy(&vht_cap->vht_mcs, + &macinfo->vht_cap.supp_mcs, + sizeof(struct ieee80211_vht_mcs_info)); + } +} + +struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus) +{ + struct wiphy *wiphy; + + wiphy = wiphy_new(&qtn_cfg80211_ops, sizeof(struct qtnf_wmac)); + if (!wiphy) + return NULL; + + set_wiphy_dev(wiphy, bus->dev); + + return wiphy; +} + +static int qtnf_wiphy_setup_if_comb(struct wiphy *wiphy, + struct ieee80211_iface_combination *if_comb, + const struct qtnf_mac_info *mac_info) +{ + size_t max_interfaces = 0; + u16 interface_modes = 0; + size_t i; + + if (unlikely(!mac_info->limits || !mac_info->n_limits)) + return -ENOENT; + + if_comb->limits = mac_info->limits; + if_comb->n_limits = mac_info->n_limits; + + for (i = 0; i < mac_info->n_limits; i++) { + max_interfaces += mac_info->limits[i].max; + interface_modes |= mac_info->limits[i].types; + } + + if_comb->num_different_channels = 1; + if_comb->beacon_int_infra_match = true; + if_comb->max_interfaces = max_interfaces; + if_comb->radar_detect_widths = mac_info->radar_detect_widths; + wiphy->interface_modes = interface_modes; + + return 0; +} + +int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + struct ieee80211_iface_combination *iface_comb = NULL; + int ret; + + if (!wiphy) { + pr_err("invalid wiphy pointer\n"); + return -EFAULT; + } + + iface_comb = kzalloc(sizeof(*iface_comb), GFP_KERNEL); + if (!iface_comb) { + ret = -ENOMEM; + goto out; + } + + ret = qtnf_wiphy_setup_if_comb(wiphy, iface_comb, &mac->macinfo); + if (ret) + goto out; + + pr_info("MAC%u: phymode=%#x radar=%#x\n", mac->macid, + mac->macinfo.phymode_cap, mac->macinfo.radar_detect_widths); + + wiphy->frag_threshold = mac->macinfo.frag_thr; + wiphy->rts_threshold = mac->macinfo.rts_thr; + wiphy->retry_short = mac->macinfo.sretry_limit; + wiphy->retry_long = mac->macinfo.lretry_limit; + wiphy->coverage_class = mac->macinfo.coverage_class; + + wiphy->max_scan_ssids = QTNF_MAX_SSID_LIST_LENGTH; + wiphy->max_scan_ie_len = QTNF_MAX_VSIE_LEN; + wiphy->mgmt_stypes = qtnf_mgmt_stypes; + wiphy->max_remain_on_channel_duration = 5000; + + wiphy->iface_combinations = iface_comb; + wiphy->n_iface_combinations = 1; + + /* Initialize cipher suits */ + wiphy->cipher_suites = qtnf_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(qtnf_cipher_suites); + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | + WIPHY_FLAG_AP_UAPSD; + + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; + + wiphy->available_antennas_tx = mac->macinfo.num_tx_chain; + wiphy->available_antennas_rx = mac->macinfo.num_rx_chain; + + wiphy->max_ap_assoc_sta = mac->macinfo.max_ap_assoc_sta; + + ether_addr_copy(wiphy->perm_addr, mac->macaddr); + + if (hw_info->hw_capab & QLINK_HW_SUPPORTS_REG_UPDATE) { + pr_debug("device supports REG_UPDATE\n"); + wiphy->reg_notifier = qtnf_cfg80211_reg_notifier; + pr_debug("hint regulatory about EP region: %c%c\n", + hw_info->alpha2_code[0], + hw_info->alpha2_code[1]); + regulatory_hint(wiphy, hw_info->alpha2_code); + } else { + pr_debug("device doesn't support REG_UPDATE\n"); + wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; + } + + ret = wiphy_register(wiphy); + +out: + if (ret < 0) { + kfree(iface_comb); + return ret; + } + + return 0; +} + +void qtnf_netdev_updown(struct net_device *ndev, bool up) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + + if (qtnf_cmd_send_updown_intf(vif, up)) + pr_err("failed to send up/down command to FW\n"); +} + +void qtnf_virtual_intf_cleanup(struct net_device *ndev) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + struct qtnf_wmac *mac = wiphy_priv(vif->wdev.wiphy); + + if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { + switch (vif->sta_state) { + case QTNF_STA_DISCONNECTED: + break; + case QTNF_STA_CONNECTING: + cfg80211_connect_result(vif->netdev, + vif->bss_cfg.bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + qtnf_disconnect(vif->wdev.wiphy, ndev, + WLAN_REASON_DEAUTH_LEAVING); + break; + case QTNF_STA_CONNECTED: + cfg80211_disconnected(vif->netdev, + WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, 1, GFP_KERNEL); + qtnf_disconnect(vif->wdev.wiphy, ndev, + WLAN_REASON_DEAUTH_LEAVING); + break; + } + + vif->sta_state = QTNF_STA_DISCONNECTED; + qtnf_scan_done(mac, true); + } +} + +void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif) +{ + if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { + switch (vif->sta_state) { + case QTNF_STA_CONNECTING: + cfg80211_connect_result(vif->netdev, + vif->bss_cfg.bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + break; + case QTNF_STA_CONNECTED: + cfg80211_disconnected(vif->netdev, + WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, 1, GFP_KERNEL); + break; + case QTNF_STA_DISCONNECTED: + break; + } + } + + cfg80211_shutdown_all_interfaces(vif->wdev.wiphy); + vif->sta_state = QTNF_STA_DISCONNECTED; +} + +void qtnf_band_init_rates(struct ieee80211_supported_band *band) +{ + switch (band->band) { + case NL80211_BAND_2GHZ: + band->bitrates = qtnf_rates_2g; + band->n_bitrates = ARRAY_SIZE(qtnf_rates_2g); + break; + case NL80211_BAND_5GHZ: + band->bitrates = qtnf_rates_5g; + band->n_bitrates = ARRAY_SIZE(qtnf_rates_5g); + break; + default: + band->bitrates = NULL; + band->n_bitrates = 0; + break; + } +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h new file mode 100644 index 000000000000..5bd33124a7c8 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_CFG80211_H_ +#define _QTN_FMAC_CFG80211_H_ + +#include <net/cfg80211.h> + +#include "core.h" + +int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac); +int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); +void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif); +void qtnf_band_init_rates(struct ieee80211_supported_band *band); +void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo, + struct ieee80211_supported_band *band); + +static inline void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + + if (mac->scan_req) { + cfg80211_scan_done(mac->scan_req, &info); + mac->scan_req = NULL; + } +} + +#endif /* _QTN_FMAC_CFG80211_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c new file mode 100644 index 000000000000..b39dbc3d3c1f --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -0,0 +1,1978 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/types.h> +#include <linux/skbuff.h> + +#include "cfg80211.h" +#include "core.h" +#include "qlink.h" +#include "qlink_util.h" +#include "bus.h" +#include "commands.h" + +static int qtnf_cmd_check_reply_header(const struct qlink_resp *resp, + u16 cmd_id, u8 mac_id, u8 vif_id, + size_t resp_size) +{ + if (unlikely(le16_to_cpu(resp->cmd_id) != cmd_id)) { + pr_warn("VIF%u.%u CMD%x: bad cmd_id in response: 0x%.4X\n", + mac_id, vif_id, cmd_id, le16_to_cpu(resp->cmd_id)); + return -EINVAL; + } + + if (unlikely(resp->macid != mac_id)) { + pr_warn("VIF%u.%u CMD%x: bad MAC in response: %u\n", + mac_id, vif_id, cmd_id, resp->macid); + return -EINVAL; + } + + if (unlikely(resp->vifid != vif_id)) { + pr_warn("VIF%u.%u CMD%x: bad VIF in response: %u\n", + mac_id, vif_id, cmd_id, resp->vifid); + return -EINVAL; + } + + if (unlikely(le16_to_cpu(resp->mhdr.len) < resp_size)) { + pr_warn("VIF%u.%u CMD%x: bad response size %u < %zu\n", + mac_id, vif_id, cmd_id, + le16_to_cpu(resp->mhdr.len), resp_size); + return -ENOSPC; + } + + return 0; +} + +static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, + struct sk_buff *cmd_skb, + struct sk_buff **response_skb, + u16 *result_code, + size_t const_resp_size, + size_t *var_resp_size) +{ + struct qlink_cmd *cmd; + const struct qlink_resp *resp; + struct sk_buff *resp_skb = NULL; + u16 cmd_id; + u8 mac_id, vif_id; + int ret; + + cmd = (struct qlink_cmd *)cmd_skb->data; + cmd_id = le16_to_cpu(cmd->cmd_id); + mac_id = cmd->macid; + vif_id = cmd->vifid; + cmd->mhdr.len = cpu_to_le16(cmd_skb->len); + + if (unlikely(bus->fw_state != QTNF_FW_STATE_ACTIVE && + le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT)) { + pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n", + mac_id, vif_id, le16_to_cpu(cmd->cmd_id), + bus->fw_state); + return -ENODEV; + } + + pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, + le16_to_cpu(cmd->cmd_id)); + + ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb); + + if (unlikely(ret)) + goto out; + + resp = (const struct qlink_resp *)resp_skb->data; + ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id, + const_resp_size); + + if (unlikely(ret)) + goto out; + + if (likely(result_code)) + *result_code = le16_to_cpu(resp->result); + + /* Return length of variable part of response */ + if (response_skb && var_resp_size) + *var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size; + +out: + if (response_skb) + *response_skb = resp_skb; + else + consume_skb(resp_skb); + + return ret; +} + +static inline int qtnf_cmd_send(struct qtnf_bus *bus, + struct sk_buff *cmd_skb, + u16 *result_code) +{ + return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, result_code, + sizeof(struct qlink_resp), NULL); +} + +static struct sk_buff *qtnf_cmd_alloc_new_cmdskb(u8 macid, u8 vifid, u16 cmd_no, + size_t cmd_size) +{ + struct qlink_cmd *cmd; + struct sk_buff *cmd_skb; + + cmd_skb = __dev_alloc_skb(sizeof(*cmd) + + QTNF_MAX_CMD_BUF_SIZE, GFP_KERNEL); + if (unlikely(!cmd_skb)) { + pr_err("VIF%u.%u CMD %u: alloc failed\n", macid, vifid, cmd_no); + return NULL; + } + + skb_put_zero(cmd_skb, cmd_size); + + cmd = (struct qlink_cmd *)cmd_skb->data; + cmd->mhdr.len = cpu_to_le16(cmd_skb->len); + cmd->mhdr.type = cpu_to_le16(QLINK_MSG_TYPE_CMD); + cmd->cmd_id = cpu_to_le16(cmd_no); + cmd->macid = macid; + cmd->vifid = vifid; + + return cmd_skb; +} + +int qtnf_cmd_send_start_ap(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_START_AP, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + + vif->bss_status |= QTNF_STATE_AP_START; + netif_carrier_on(vif->netdev); + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_regulatory_config(struct qtnf_wmac *mac, const char *alpha2) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, + QLINK_CMD_REG_REGION, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_COUNTRY, alpha2, + QTNF_MAX_ALPHA_LEN); + + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + memcpy(mac->bus->hw_info.alpha2_code, alpha2, + sizeof(mac->bus->hw_info.alpha2_code)); +out: + return ret; +} + +int qtnf_cmd_send_config_ap(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + struct qtnf_bss_config *bss_cfg = &vif->bss_cfg; + struct cfg80211_chan_def *chandef = &bss_cfg->chandef; + struct qlink_tlv_channel *qchan; + struct qlink_auth_encr aen; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + int i; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_CONFIG_AP, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, bss_cfg->ssid, + bss_cfg->ssid_len); + qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_BCN_PERIOD, + bss_cfg->bcn_period); + qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_DTIM, bss_cfg->dtim); + + qchan = skb_put_zero(cmd_skb, sizeof(*qchan)); + qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); + qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - + sizeof(struct qlink_tlv_hdr)); + qchan->hw_value = cpu_to_le16( + ieee80211_frequency_to_channel(chandef->chan->center_freq)); + + memset(&aen, 0, sizeof(aen)); + aen.auth_type = bss_cfg->auth_type; + aen.privacy = !!bss_cfg->privacy; + aen.mfp = bss_cfg->mfp; + aen.wpa_versions = cpu_to_le32(bss_cfg->crypto.wpa_versions); + aen.cipher_group = cpu_to_le32(bss_cfg->crypto.cipher_group); + aen.n_ciphers_pairwise = cpu_to_le32( + bss_cfg->crypto.n_ciphers_pairwise); + for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) + aen.ciphers_pairwise[i] = cpu_to_le32( + bss_cfg->crypto.ciphers_pairwise[i]); + aen.n_akm_suites = cpu_to_le32( + bss_cfg->crypto.n_akm_suites); + for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + aen.akm_suites[i] = cpu_to_le32( + bss_cfg->crypto.akm_suites[i]); + aen.control_port = bss_cfg->crypto.control_port; + aen.control_port_no_encrypt = + bss_cfg->crypto.control_port_no_encrypt; + aen.control_port_ethertype = cpu_to_le16(be16_to_cpu( + bss_cfg->crypto.control_port_ethertype)); + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_CRYPTO, (u8 *)&aen, + sizeof(aen)); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + + vif->bss_status |= QTNF_STATE_AP_CONFIG; + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_STOP_AP, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + + vif->bss_status &= ~QTNF_STATE_AP_START; + vif->bss_status &= ~QTNF_STATE_AP_CONFIG; + + netif_carrier_off(vif->netdev); + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_mgmt_frame_register *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_REGISTER_MGMT, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_mgmt_frame_register *)cmd_skb->data; + cmd->frame_type = cpu_to_le16(frame_type); + cmd->do_register = reg; + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, + u16 freq, const u8 *buf, size_t len) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_mgmt_frame_tx *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { + pr_warn("VIF%u.%u: frame is too big: %zu\n", vif->mac->macid, + vif->vifid, len); + return -E2BIG; + } + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_SEND_MGMT_FRAME, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_mgmt_frame_tx *)cmd_skb->data; + cmd->cookie = cpu_to_le32(cookie); + cmd->freq = cpu_to_le16(freq); + cmd->flags = cpu_to_le16(flags); + + if (len && buf) + qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, + const u8 *buf, size_t len) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_mgmt_append_ie *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { + pr_warn("VIF%u.%u: %u frame is too big: %zu\n", vif->mac->macid, + vif->vifid, frame_type, len); + return -E2BIG; + } + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_MGMT_SET_APPIE, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_mgmt_append_ie *)cmd_skb->data; + cmd->type = frame_type; + cmd->flags = 0; + + /* If len == 0 then IE buf for specified frame type + * should be cleared on EP. + */ + if (len && buf) + qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u frame %u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, frame_type, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +static void +qtnf_sta_info_parse_basic_counters(struct station_info *sinfo, + const struct qlink_sta_stat_basic_counters *counters) +{ + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES) | + BIT(NL80211_STA_INFO_TX_BYTES); + sinfo->rx_bytes = get_unaligned_le64(&counters->rx_bytes); + sinfo->tx_bytes = get_unaligned_le64(&counters->tx_bytes); + + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_BEACON_RX); + sinfo->rx_packets = get_unaligned_le32(&counters->rx_packets); + sinfo->tx_packets = get_unaligned_le32(&counters->tx_packets); + sinfo->rx_beacon = get_unaligned_le64(&counters->rx_beacons); + + sinfo->filled |= BIT(NL80211_STA_INFO_RX_DROP_MISC) | + BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->rx_dropped_misc = get_unaligned_le32(&counters->rx_dropped); + sinfo->tx_failed = get_unaligned_le32(&counters->tx_failed); +} + +static void +qtnf_sta_info_parse_rate(struct rate_info *rate_dst, + const struct qlink_sta_info_rate *rate_src) +{ + rate_dst->legacy = get_unaligned_le16(&rate_src->rate) * 10; + + rate_dst->mcs = rate_src->mcs; + rate_dst->nss = rate_src->nss; + rate_dst->flags = 0; + + switch (rate_src->bw) { + case QLINK_STA_INFO_RATE_BW_5: + rate_dst->bw = RATE_INFO_BW_5; + break; + case QLINK_STA_INFO_RATE_BW_10: + rate_dst->bw = RATE_INFO_BW_10; + break; + case QLINK_STA_INFO_RATE_BW_20: + rate_dst->bw = RATE_INFO_BW_20; + break; + case QLINK_STA_INFO_RATE_BW_40: + rate_dst->bw = RATE_INFO_BW_40; + break; + case QLINK_STA_INFO_RATE_BW_80: + rate_dst->bw = RATE_INFO_BW_80; + break; + case QLINK_STA_INFO_RATE_BW_160: + rate_dst->bw = RATE_INFO_BW_160; + break; + default: + rate_dst->bw = 0; + break; + } + + if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HT_MCS) + rate_dst->flags |= RATE_INFO_FLAGS_MCS; + else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS) + rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS; +} + +static void +qtnf_sta_info_parse_flags(struct nl80211_sta_flag_update *dst, + const struct qlink_sta_info_state *src) +{ + u32 mask, value; + + dst->mask = 0; + dst->set = 0; + + mask = le32_to_cpu(src->mask); + value = le32_to_cpu(src->value); + + if (mask & QLINK_STA_FLAG_AUTHORIZED) { + dst->mask |= BIT(NL80211_STA_FLAG_AUTHORIZED); + if (value & QLINK_STA_FLAG_AUTHORIZED) + dst->set |= BIT(NL80211_STA_FLAG_AUTHORIZED); + } + + if (mask & QLINK_STA_FLAG_SHORT_PREAMBLE) { + dst->mask |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + if (value & QLINK_STA_FLAG_SHORT_PREAMBLE) + dst->set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + } + + if (mask & QLINK_STA_FLAG_WME) { + dst->mask |= BIT(NL80211_STA_FLAG_WME); + if (value & QLINK_STA_FLAG_WME) + dst->set |= BIT(NL80211_STA_FLAG_WME); + } + + if (mask & QLINK_STA_FLAG_MFP) { + dst->mask |= BIT(NL80211_STA_FLAG_MFP); + if (value & QLINK_STA_FLAG_MFP) + dst->set |= BIT(NL80211_STA_FLAG_MFP); + } + + if (mask & QLINK_STA_FLAG_AUTHENTICATED) { + dst->mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED); + if (value & QLINK_STA_FLAG_AUTHENTICATED) + dst->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); + } + + if (mask & QLINK_STA_FLAG_TDLS_PEER) { + dst->mask |= BIT(NL80211_STA_FLAG_TDLS_PEER); + if (value & QLINK_STA_FLAG_TDLS_PEER) + dst->set |= BIT(NL80211_STA_FLAG_TDLS_PEER); + } + + if (mask & QLINK_STA_FLAG_ASSOCIATED) { + dst->mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); + if (value & QLINK_STA_FLAG_ASSOCIATED) + dst->set |= BIT(NL80211_STA_FLAG_ASSOCIATED); + } +} + +static void +qtnf_sta_info_parse_generic_info(struct station_info *sinfo, + const struct qlink_sta_info_generic *info) +{ + sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME) | + BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->connected_time = get_unaligned_le32(&info->connected_time); + sinfo->inactive_time = get_unaligned_le32(&info->inactive_time); + + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) | + BIT(NL80211_STA_INFO_SIGNAL_AVG); + sinfo->signal = info->rssi - 120; + sinfo->signal_avg = info->rssi_avg - QLINK_RSSI_OFFSET; + + if (info->rx_rate.rate) { + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + qtnf_sta_info_parse_rate(&sinfo->rxrate, &info->rx_rate); + } + + if (info->tx_rate.rate) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + qtnf_sta_info_parse_rate(&sinfo->txrate, &info->tx_rate); + } + + sinfo->filled |= BIT(NL80211_STA_INFO_STA_FLAGS); + qtnf_sta_info_parse_flags(&sinfo->sta_flags, &info->state); +} + +static int qtnf_cmd_sta_info_parse(struct station_info *sinfo, + const u8 *payload, size_t payload_size) +{ + const struct qlink_sta_stat_basic_counters *counters; + const struct qlink_sta_info_generic *sta_info; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + sinfo->filled = 0; + + tlv = (const struct qlink_tlv_hdr *)payload; + while (payload_size >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + if (tlv_full_len > payload_size) { + pr_warn("malformed TLV 0x%.2X; LEN: %u\n", + tlv_type, tlv_value_len); + return -EINVAL; + } + switch (tlv_type) { + case QTN_TLV_ID_STA_BASIC_COUNTERS: + if (unlikely(tlv_value_len < sizeof(*counters))) { + pr_err("invalid TLV size %.4X: %u\n", + tlv_type, tlv_value_len); + break; + } + + counters = (void *)tlv->val; + qtnf_sta_info_parse_basic_counters(sinfo, counters); + break; + case QTN_TLV_ID_STA_GENERIC_INFO: + if (unlikely(tlv_value_len < sizeof(*sta_info))) + break; + + sta_info = (void *)tlv->val; + qtnf_sta_info_parse_generic_info(sinfo, sta_info); + break; + default: + pr_warn("unexpected TLV type: %.4X\n", tlv_type); + break; + } + payload_size -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_size) { + pr_warn("malformed TLV buf; bytes left: %zu\n", payload_size); + return -EINVAL; + } + + return 0; +} + +int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, + struct station_info *sinfo) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + struct qlink_cmd_get_sta_info *cmd; + const struct qlink_resp_get_sta_info *resp; + size_t var_resp_len; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_GET_STA_INFO, + sizeof(*cmd)); + + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_get_sta_info *)cmd_skb->data; + ether_addr_copy(cmd->sta_addr, sta_mac); + + ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, + &res_code, sizeof(*resp), + &var_resp_len); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + switch (res_code) { + case QLINK_CMD_RESULT_ENOTFOUND: + pr_warn("VIF%u.%u: %pM STA not found\n", + vif->mac->macid, vif->vifid, sta_mac); + ret = -ENOENT; + break; + default: + pr_err("VIF%u.%u: can't get info for %pM: %u\n", + vif->mac->macid, vif->vifid, sta_mac, res_code); + ret = -EFAULT; + break; + } + goto out; + } + + resp = (const struct qlink_resp_get_sta_info *)resp_skb->data; + + if (unlikely(!ether_addr_equal(sta_mac, resp->sta_addr))) { + pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n", + vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac); + ret = -EINVAL; + goto out; + } + + ret = qtnf_cmd_sta_info_parse(sinfo, resp->info, var_resp_len); + +out: + qtnf_bus_unlock(vif->mac->bus); + consume_skb(resp_skb); + + return ret; +} + +static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, + enum nl80211_iftype iftype, + u8 *mac_addr, + enum qlink_cmd_type cmd_type) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + struct qlink_cmd_manage_intf *cmd; + const struct qlink_resp_manage_intf *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + cmd_type, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data; + + switch (iftype) { + case NL80211_IFTYPE_AP: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP); + break; + case NL80211_IFTYPE_STATION: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION); + break; + default: + pr_err("VIF%u.%u: unsupported type %d\n", vif->mac->macid, + vif->vifid, iftype); + ret = -EINVAL; + goto out; + } + + if (mac_addr) + ether_addr_copy(cmd->intf_info.mac_addr, mac_addr); + else + eth_zero_addr(cmd->intf_info.mac_addr); + + ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, + &res_code, sizeof(*resp), NULL); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid, + vif->vifid, cmd_type, res_code); + ret = -EFAULT; + goto out; + } + + resp = (const struct qlink_resp_manage_intf *)resp_skb->data; + ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr); + +out: + qtnf_bus_unlock(vif->mac->bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, + enum nl80211_iftype iftype, u8 *mac_addr) +{ + return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr, + QLINK_CMD_ADD_INTF); +} + +int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif, + enum nl80211_iftype iftype, u8 *mac_addr) +{ + return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr, + QLINK_CMD_CHANGE_INTF); +} + +int qtnf_cmd_send_del_intf(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_manage_intf *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DEL_INTF, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data; + + switch (vif->wdev.iftype) { + case NL80211_IFTYPE_AP: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP); + break; + case NL80211_IFTYPE_STATION: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION); + break; + default: + pr_warn("VIF%u.%u: unsupported iftype %d\n", vif->mac->macid, + vif->vifid, vif->wdev.iftype); + ret = -EINVAL; + goto out; + } + + eth_zero_addr(cmd->intf_info.mac_addr); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +static int +qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, + const struct qlink_resp_get_hw_info *resp) +{ + struct qtnf_hw_info *hwinfo = &bus->hw_info; + + hwinfo->num_mac = resp->num_mac; + hwinfo->mac_bitmap = resp->mac_bitmap; + hwinfo->fw_ver = le32_to_cpu(resp->fw_ver); + hwinfo->ql_proto_ver = le16_to_cpu(resp->ql_proto_ver); + memcpy(hwinfo->alpha2_code, resp->alpha2_code, + sizeof(hwinfo->alpha2_code)); + hwinfo->total_tx_chain = resp->total_tx_chain; + hwinfo->total_rx_chain = resp->total_rx_chain; + hwinfo->hw_capab = le32_to_cpu(resp->hw_capab); + + pr_info("fw_version=%d, MACs map %#x, alpha2=\"%c%c\", chains Tx=%u Rx=%u\n", + hwinfo->fw_ver, hwinfo->mac_bitmap, + hwinfo->alpha2_code[0], hwinfo->alpha2_code[1], + hwinfo->total_tx_chain, hwinfo->total_rx_chain); + + return 0; +} + +static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, + const u8 *tlv_buf, size_t tlv_buf_size) +{ + struct ieee80211_iface_limit *limits = NULL; + const struct qlink_iface_limit *limit_record; + size_t record_count = 0, rec = 0; + u16 tlv_type, tlv_value_len, mask; + struct qlink_iface_comb_num *comb; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + mac->macinfo.n_limits = 0; + + tlv = (const struct qlink_tlv_hdr *)tlv_buf; + while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + if (tlv_full_len > tlv_buf_size) { + pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n", + mac->macid, tlv_type, tlv_value_len); + return -EINVAL; + } + + switch (tlv_type) { + case QTN_TLV_ID_NUM_IFACE_COMB: + if (unlikely(tlv_value_len != sizeof(*comb))) + return -EINVAL; + + comb = (void *)tlv->val; + record_count = le16_to_cpu(comb->iface_comb_num); + + mac->macinfo.n_limits = record_count; + /* free earlier iface limits memory */ + kfree(mac->macinfo.limits); + mac->macinfo.limits = + kzalloc(sizeof(*mac->macinfo.limits) * + record_count, GFP_KERNEL); + + if (unlikely(!mac->macinfo.limits)) + return -ENOMEM; + + limits = mac->macinfo.limits; + break; + case QTN_TLV_ID_IFACE_LIMIT: + if (unlikely(!limits)) { + pr_warn("MAC%u: limits are not inited\n", + mac->macid); + return -EINVAL; + } + + if (unlikely(tlv_value_len != sizeof(*limit_record))) { + pr_warn("MAC%u: record size mismatch\n", + mac->macid); + return -EINVAL; + } + + limit_record = (void *)tlv->val; + limits[rec].max = le16_to_cpu(limit_record->max_num); + mask = le16_to_cpu(limit_record->type_mask); + limits[rec].types = qlink_iface_type_mask_to_nl(mask); + /* only AP and STA modes are supported */ + limits[rec].types &= BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION); + + pr_debug("MAC%u: MAX: %u; TYPES: %.4X\n", mac->macid, + limits[rec].max, limits[rec].types); + + if (limits[rec].types) + rec++; + break; + default: + break; + } + tlv_buf_size -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (tlv_buf_size) { + pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n", + mac->macid, tlv_buf_size); + return -EINVAL; + } + + if (mac->macinfo.n_limits != rec) { + pr_err("MAC%u: combination mismatch: reported=%zu parsed=%zu\n", + mac->macid, mac->macinfo.n_limits, rec); + return -EINVAL; + } + + return 0; +} + +static void +qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac, + const struct qlink_resp_get_mac_info *resp_info) +{ + struct qtnf_mac_info *mac_info; + struct qtnf_vif *vif; + + mac_info = &mac->macinfo; + + mac_info->bands_cap = resp_info->bands_cap; + mac_info->phymode_cap = resp_info->phymode_cap; + memcpy(&mac_info->dev_mac, &resp_info->dev_mac, + sizeof(mac_info->dev_mac)); + + ether_addr_copy(mac->macaddr, mac_info->dev_mac); + + vif = qtnf_mac_get_base_vif(mac); + if (vif) + ether_addr_copy(vif->mac_addr, mac->macaddr); + else + pr_err("could not get valid base vif\n"); + + mac_info->num_tx_chain = resp_info->num_tx_chain; + mac_info->num_rx_chain = resp_info->num_rx_chain; + + mac_info->max_ap_assoc_sta = le16_to_cpu(resp_info->max_ap_assoc_sta); + mac_info->radar_detect_widths = + qlink_chan_width_mask_to_nl(le16_to_cpu( + resp_info->radar_detect_widths)); + + memcpy(&mac_info->ht_cap, &resp_info->ht_cap, sizeof(mac_info->ht_cap)); + memcpy(&mac_info->vht_cap, &resp_info->vht_cap, + sizeof(mac_info->vht_cap)); +} + +static int +qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band, + struct qlink_resp_get_chan_info *resp, + size_t payload_len) +{ + u16 tlv_type; + size_t tlv_len; + const struct qlink_tlv_hdr *tlv; + const struct qlink_tlv_channel *qchan; + struct ieee80211_channel *chan; + unsigned int chidx = 0; + u32 qflags; + + kfree(band->channels); + band->channels = NULL; + + band->n_channels = resp->num_chans; + if (band->n_channels == 0) + return 0; + + band->channels = kcalloc(band->n_channels, sizeof(*chan), GFP_KERNEL); + if (!band->channels) { + band->n_channels = 0; + return -ENOMEM; + } + + tlv = (struct qlink_tlv_hdr *)resp->info; + + while (payload_len >= sizeof(*tlv)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_len = le16_to_cpu(tlv->len) + sizeof(*tlv); + + if (tlv_len > payload_len) { + pr_warn("malformed TLV 0x%.2X; LEN: %zu\n", + tlv_type, tlv_len); + goto error_ret; + } + + switch (tlv_type) { + case QTN_TLV_ID_CHANNEL: + if (unlikely(tlv_len != sizeof(*qchan))) { + pr_err("invalid channel TLV len %zu\n", + tlv_len); + goto error_ret; + } + + if (chidx == band->n_channels) { + pr_err("too many channel TLVs\n"); + goto error_ret; + } + + qchan = (const struct qlink_tlv_channel *)tlv; + chan = &band->channels[chidx++]; + qflags = le32_to_cpu(qchan->flags); + + chan->hw_value = le16_to_cpu(qchan->hw_value); + chan->band = band->band; + chan->center_freq = le16_to_cpu(qchan->center_freq); + chan->max_antenna_gain = (int)qchan->max_antenna_gain; + chan->max_power = (int)qchan->max_power; + chan->max_reg_power = (int)qchan->max_reg_power; + chan->beacon_found = qchan->beacon_found; + chan->dfs_cac_ms = le32_to_cpu(qchan->dfs_cac_ms); + chan->flags = 0; + + if (qflags & QLINK_CHAN_DISABLED) + chan->flags |= IEEE80211_CHAN_DISABLED; + + if (qflags & QLINK_CHAN_NO_IR) + chan->flags |= IEEE80211_CHAN_NO_IR; + + if (qflags & QLINK_CHAN_NO_HT40PLUS) + chan->flags |= IEEE80211_CHAN_NO_HT40PLUS; + + if (qflags & QLINK_CHAN_NO_HT40MINUS) + chan->flags |= IEEE80211_CHAN_NO_HT40MINUS; + + if (qflags & QLINK_CHAN_NO_OFDM) + chan->flags |= IEEE80211_CHAN_NO_OFDM; + + if (qflags & QLINK_CHAN_NO_80MHZ) + chan->flags |= IEEE80211_CHAN_NO_80MHZ; + + if (qflags & QLINK_CHAN_NO_160MHZ) + chan->flags |= IEEE80211_CHAN_NO_160MHZ; + + if (qflags & QLINK_CHAN_INDOOR_ONLY) + chan->flags |= IEEE80211_CHAN_INDOOR_ONLY; + + if (qflags & QLINK_CHAN_IR_CONCURRENT) + chan->flags |= IEEE80211_CHAN_IR_CONCURRENT; + + if (qflags & QLINK_CHAN_NO_20MHZ) + chan->flags |= IEEE80211_CHAN_NO_20MHZ; + + if (qflags & QLINK_CHAN_NO_10MHZ) + chan->flags |= IEEE80211_CHAN_NO_10MHZ; + + if (qflags & QLINK_CHAN_RADAR) { + chan->flags |= IEEE80211_CHAN_RADAR; + chan->dfs_state_entered = jiffies; + + if (qchan->dfs_state == QLINK_DFS_USABLE) + chan->dfs_state = NL80211_DFS_USABLE; + else if (qchan->dfs_state == + QLINK_DFS_AVAILABLE) + chan->dfs_state = NL80211_DFS_AVAILABLE; + else + chan->dfs_state = + NL80211_DFS_UNAVAILABLE; + } + + pr_debug("chan=%d flags=%#x max_pow=%d max_reg_pow=%d\n", + chan->hw_value, chan->flags, chan->max_power, + chan->max_reg_power); + break; + default: + pr_warn("unknown TLV type: %#x\n", tlv_type); + break; + } + + payload_len -= tlv_len; + tlv = (struct qlink_tlv_hdr *)((u8 *)tlv + tlv_len); + } + + if (payload_len) { + pr_err("malformed TLV buf; bytes left: %zu\n", payload_len); + goto error_ret; + } + + if (band->n_channels != chidx) { + pr_err("channel count mismatch: reported=%d, parsed=%d\n", + band->n_channels, chidx); + goto error_ret; + } + + return 0; + +error_ret: + kfree(band->channels); + band->channels = NULL; + band->n_channels = 0; + + return -EINVAL; +} + +static int qtnf_cmd_resp_proc_phy_params(struct qtnf_wmac *mac, + const u8 *payload, size_t payload_len) +{ + struct qtnf_mac_info *mac_info; + struct qlink_tlv_frag_rts_thr *phy_thr; + struct qlink_tlv_rlimit *limit; + struct qlink_tlv_cclass *class; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + mac_info = &mac->macinfo; + + tlv = (struct qlink_tlv_hdr *)payload; + while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + + if (tlv_full_len > payload_len) { + pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n", + mac->macid, tlv_type, tlv_value_len); + return -EINVAL; + } + + switch (tlv_type) { + case QTN_TLV_ID_FRAG_THRESH: + phy_thr = (void *)tlv; + mac_info->frag_thr = (u32)le16_to_cpu(phy_thr->thr); + break; + case QTN_TLV_ID_RTS_THRESH: + phy_thr = (void *)tlv; + mac_info->rts_thr = (u32)le16_to_cpu(phy_thr->thr); + break; + case QTN_TLV_ID_SRETRY_LIMIT: + limit = (void *)tlv; + mac_info->sretry_limit = limit->rlimit; + break; + case QTN_TLV_ID_LRETRY_LIMIT: + limit = (void *)tlv; + mac_info->lretry_limit = limit->rlimit; + break; + case QTN_TLV_ID_COVERAGE_CLASS: + class = (void *)tlv; + mac_info->coverage_class = class->cclass; + break; + default: + pr_err("MAC%u: Unknown TLV type: %#x\n", mac->macid, + le16_to_cpu(tlv->type)); + break; + } + + payload_len -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_len) { + pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n", + mac->macid, payload_len); + return -EINVAL; + } + + return 0; +} + +int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + const struct qlink_resp_get_mac_info *resp; + size_t var_data_len; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, + QLINK_CMD_MAC_INFO, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), &var_data_len); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + resp = (const struct qlink_resp_get_mac_info *)resp_skb->data; + qtnf_cmd_resp_proc_mac_info(mac, resp); + ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len); + +out: + qtnf_bus_unlock(mac->bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_get_hw_info(struct qtnf_bus *bus) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + const struct qlink_resp_get_hw_info *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, + QLINK_CMD_GET_HW_INFO, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), NULL); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("cmd exec failed: 0x%.4X\n", res_code); + ret = -EFAULT; + goto out; + } + + resp = (const struct qlink_resp_get_hw_info *)resp_skb->data; + ret = qtnf_cmd_resp_proc_hw_info(bus, resp); + +out: + qtnf_bus_unlock(bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, + struct ieee80211_supported_band *band) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + size_t info_len; + struct qlink_cmd_chans_info_get *cmd; + struct qlink_resp_get_chan_info *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + u8 qband; + + switch (band->band) { + case NL80211_BAND_2GHZ: + qband = QLINK_BAND_2GHZ; + break; + case NL80211_BAND_5GHZ: + qband = QLINK_BAND_5GHZ; + break; + case NL80211_BAND_60GHZ: + qband = QLINK_BAND_60GHZ; + break; + default: + return -EINVAL; + } + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, + QLINK_CMD_CHANS_INFO_GET, + sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + cmd = (struct qlink_cmd_chans_info_get *)cmd_skb->data; + cmd->band = qband; + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), &info_len); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + resp = (struct qlink_resp_get_chan_info *)resp_skb->data; + if (resp->band != qband) { + pr_err("MAC%u: reply band %u != cmd band %u\n", mac->macid, + resp->band, qband); + ret = -EINVAL; + goto out; + } + + ret = qtnf_cmd_resp_fill_channels_info(band, resp, info_len); + +out: + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + size_t response_size; + struct qlink_resp_phy_params *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, + QLINK_CMD_PHY_PARAMS_GET, + sizeof(struct qlink_cmd)); + if (!cmd_skb) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), &response_size); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + resp = (struct qlink_resp_phy_params *)resp_skb->data; + ret = qtnf_cmd_resp_proc_phy_params(mac, resp->info, response_size); + +out: + qtnf_bus_unlock(mac->bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, + QLINK_CMD_PHY_PARAMS_SET, + sizeof(struct qlink_cmd)); + if (!cmd_skb) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_FRAG_THRESH, + wiphy->frag_threshold); + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_RTS_THRESH, + wiphy->rts_threshold); + if (changed & WIPHY_PARAM_COVERAGE_CLASS) + qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS, + wiphy->coverage_class); + + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(mac->bus); + return ret; +} + +int qtnf_cmd_send_init_fw(struct qtnf_bus *bus) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, + QLINK_CMD_FW_INIT, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send(bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("cmd exec failed: 0x%.4X\n", res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(bus); + return ret; +} + +void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus) +{ + struct sk_buff *cmd_skb; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, + QLINK_CMD_FW_DEINIT, + sizeof(struct qlink_cmd)); + if (!cmd_skb) + return; + + qtnf_bus_lock(bus); + + qtnf_cmd_send(bus, cmd_skb, NULL); + + qtnf_bus_unlock(bus); +} + +int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr, struct key_params *params) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_add_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_ADD_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_add_key *)cmd_skb->data; + + if (mac_addr) + ether_addr_copy(cmd->addr, mac_addr); + else + eth_broadcast_addr(cmd->addr); + + cmd->cipher = cpu_to_le32(params->cipher); + cmd->key_index = key_index; + cmd->pairwise = pairwise; + + if (params->key && params->key_len > 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_KEY, + params->key, + params->key_len); + + if (params->seq && params->seq_len > 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_SEQ, + params->seq, + params->seq_len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", + vif->mac->macid, vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_del_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DEL_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_del_key *)cmd_skb->data; + + if (mac_addr) + ether_addr_copy(cmd->addr, mac_addr); + else + eth_broadcast_addr(cmd->addr); + + cmd->key_index = key_index; + cmd->pairwise = pairwise; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", + vif->mac->macid, vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, + bool unicast, bool multicast) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_set_def_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_SET_DEFAULT_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_set_def_key *)cmd_skb->data; + cmd->key_index = key_index; + cmd->unicast = unicast; + cmd->multicast = multicast; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_set_def_mgmt_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_SET_DEFAULT_MGMT_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data; + cmd->key_index = key_index; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +static u32 qtnf_encode_sta_flags(u32 flags) +{ + u32 code = 0; + + if (flags & BIT(NL80211_STA_FLAG_AUTHORIZED)) + code |= QLINK_STA_FLAG_AUTHORIZED; + if (flags & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) + code |= QLINK_STA_FLAG_SHORT_PREAMBLE; + if (flags & BIT(NL80211_STA_FLAG_WME)) + code |= QLINK_STA_FLAG_WME; + if (flags & BIT(NL80211_STA_FLAG_MFP)) + code |= QLINK_STA_FLAG_MFP; + if (flags & BIT(NL80211_STA_FLAG_AUTHENTICATED)) + code |= QLINK_STA_FLAG_AUTHENTICATED; + if (flags & BIT(NL80211_STA_FLAG_TDLS_PEER)) + code |= QLINK_STA_FLAG_TDLS_PEER; + if (flags & BIT(NL80211_STA_FLAG_ASSOCIATED)) + code |= QLINK_STA_FLAG_ASSOCIATED; + return code; +} + +int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, + struct station_parameters *params) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_change_sta *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_CHANGE_STA, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_change_sta *)cmd_skb->data; + ether_addr_copy(cmd->sta_addr, mac); + cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_mask)); + cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_set)); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, + struct station_del_parameters *params) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_del_sta *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DEL_STA, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_del_sta *)cmd_skb->data; + + if (params->mac) + ether_addr_copy(cmd->sta_addr, params->mac); + else + eth_broadcast_addr(cmd->sta_addr); /* flush all stations */ + + cmd->subtype = params->subtype; + cmd->reason_code = cpu_to_le16(params->reason_code); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_scan(struct qtnf_wmac *mac) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + struct ieee80211_channel *sc; + struct cfg80211_scan_request *scan_req = mac->scan_req; + struct qlink_tlv_channel *qchan; + int n_channels; + int count = 0; + int ret; + u32 flags; + + if (scan_req->n_ssids > QTNF_MAX_SSID_LIST_LENGTH) { + pr_err("MAC%u: too many SSIDs in scan request\n", mac->macid); + return -EINVAL; + } + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, + QLINK_CMD_SCAN, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + if (scan_req->n_ssids != 0) { + while (count < scan_req->n_ssids) { + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, + scan_req->ssids[count].ssid, + scan_req->ssids[count].ssid_len); + count++; + } + } + + if (scan_req->ie_len != 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_IE_SET, + scan_req->ie, + scan_req->ie_len); + + if (scan_req->n_channels) { + n_channels = scan_req->n_channels; + count = 0; + + while (n_channels != 0) { + sc = scan_req->channels[count]; + if (sc->flags & IEEE80211_CHAN_DISABLED) { + n_channels--; + continue; + } + + pr_debug("MAC%u: scan chan=%d, freq=%d, flags=%#x\n", + mac->macid, sc->hw_value, sc->center_freq, + sc->flags); + qchan = skb_put_zero(cmd_skb, sizeof(*qchan)); + flags = 0; + + qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); + qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - + sizeof(struct qlink_tlv_hdr)); + qchan->center_freq = cpu_to_le16(sc->center_freq); + qchan->hw_value = cpu_to_le16(sc->hw_value); + + if (sc->flags & IEEE80211_CHAN_NO_IR) + flags |= QLINK_CHAN_NO_IR; + + if (sc->flags & IEEE80211_CHAN_RADAR) + flags |= QLINK_CHAN_RADAR; + + qchan->flags = cpu_to_le32(flags); + n_channels--; + count++; + } + } + + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + pr_debug("MAC%u: scan started\n", mac->macid); + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(mac->bus); + return ret; +} + +int qtnf_cmd_send_connect(struct qtnf_vif *vif, + struct cfg80211_connect_params *sme) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_connect *cmd; + struct qtnf_bss_config *bss_cfg = &vif->bss_cfg; + struct qlink_auth_encr aen; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + int i; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_CONNECT, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_connect *)cmd_skb->data; + + ether_addr_copy(cmd->bssid, bss_cfg->bssid); + + if (bss_cfg->chandef.chan) + cmd->freq = cpu_to_le16(bss_cfg->chandef.chan->center_freq); + + cmd->bg_scan_period = cpu_to_le16(bss_cfg->bg_scan_period); + + memset(&aen, 0, sizeof(aen)); + aen.auth_type = bss_cfg->auth_type; + aen.privacy = !!bss_cfg->privacy; + aen.mfp = bss_cfg->mfp; + aen.wpa_versions = cpu_to_le32(bss_cfg->crypto.wpa_versions); + aen.cipher_group = cpu_to_le32(bss_cfg->crypto.cipher_group); + aen.n_ciphers_pairwise = cpu_to_le32( + bss_cfg->crypto.n_ciphers_pairwise); + + for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) + aen.ciphers_pairwise[i] = cpu_to_le32( + bss_cfg->crypto.ciphers_pairwise[i]); + + aen.n_akm_suites = cpu_to_le32(bss_cfg->crypto.n_akm_suites); + + for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + aen.akm_suites[i] = cpu_to_le32( + bss_cfg->crypto.akm_suites[i]); + + aen.control_port = bss_cfg->crypto.control_port; + aen.control_port_no_encrypt = + bss_cfg->crypto.control_port_no_encrypt; + aen.control_port_ethertype = cpu_to_le16(be16_to_cpu( + bss_cfg->crypto.control_port_ethertype)); + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, bss_cfg->ssid, + bss_cfg->ssid_len); + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_CRYPTO, (u8 *)&aen, + sizeof(aen)); + + if (sme->ie_len != 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_IE_SET, + sme->ie, + sme->ie_len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_disconnect *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DISCONNECT, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_disconnect *)cmd_skb->data; + cmd->reason = cpu_to_le16(reason_code); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_updown *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_UPDOWN_INTF, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + cmd = (struct qlink_cmd_updown *)cmd_skb->data; + cmd->if_up = !!up; + + qtnf_bus_lock(vif->mac->bus); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h new file mode 100644 index 000000000000..6c51854ef5e7 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 Quantenna Communications, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef QLINK_COMMANDS_H_ +#define QLINK_COMMANDS_H_ + +#include <linux/nl80211.h> + +#include "core.h" +#include "bus.h" + +int qtnf_cmd_send_init_fw(struct qtnf_bus *bus); +void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus); +int qtnf_cmd_get_hw_info(struct qtnf_bus *bus); +int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac); +int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, enum nl80211_iftype iftype, + u8 *mac_addr); +int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif, + enum nl80211_iftype iftype, u8 *mac_addr); +int qtnf_cmd_send_del_intf(struct qtnf_vif *vif); +int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, + struct ieee80211_supported_band *band); +int qtnf_cmd_send_regulatory_config(struct qtnf_wmac *mac, const char *alpha2); +int qtnf_cmd_send_config_ap(struct qtnf_vif *vif); +int qtnf_cmd_send_start_ap(struct qtnf_vif *vif); +int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif); +int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg); +int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, + u16 freq, const u8 *buf, size_t len); +int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, + const u8 *buf, size_t len); +int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, + struct station_info *sinfo); +int qtnf_cmd_send_phy_params(struct qtnf_wmac *mac, u16 cmd_action, + void *data_buf); +int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr, struct key_params *params); +int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr); +int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, + bool unicast, bool multicast); +int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index); +int qtnf_cmd_send_add_sta(struct qtnf_vif *vif, const u8 *mac, + struct station_parameters *params); +int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, + struct station_parameters *params); +int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, + struct station_del_parameters *params); + +int qtnf_cmd_resp_parse(struct qtnf_bus *bus, struct sk_buff *resp_skb); +int qtnf_cmd_resp_check(const struct qtnf_vif *vif, + const struct sk_buff *resp_skb, u16 cmd_id, + u16 *result, const u8 **payload, size_t *payload_size); +int qtnf_cmd_send_scan(struct qtnf_wmac *mac); +int qtnf_cmd_send_connect(struct qtnf_vif *vif, + struct cfg80211_connect_params *sme); +int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, + u16 reason_code); +int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, + bool up); + +#endif /* QLINK_COMMANDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c new file mode 100644 index 000000000000..f053532c0e87 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/if_ether.h> + +#include "core.h" +#include "bus.h" +#include "trans.h" +#include "commands.h" +#include "cfg80211.h" +#include "event.h" +#include "util.h" + +#define QTNF_DMP_MAX_LEN 48 +#define QTNF_PRIMARY_VIF_IDX 0 + +struct qtnf_frame_meta_info { + u8 magic_s; + u8 ifidx; + u8 macid; + u8 magic_e; +} __packed; + +struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid) +{ + struct qtnf_wmac *mac = NULL; + + if (unlikely(macid >= QTNF_MAX_MAC)) { + pr_err("invalid MAC index %u\n", macid); + return NULL; + } + + mac = bus->mac[macid]; + + if (unlikely(!mac)) { + pr_err("MAC%u: not initialized\n", macid); + return NULL; + } + + return mac; +} + +/* Netdev handler for open. + */ +static int qtnf_netdev_open(struct net_device *ndev) +{ + netif_carrier_off(ndev); + qtnf_netdev_updown(ndev, 1); + return 0; +} + +/* Netdev handler for close. + */ +static int qtnf_netdev_close(struct net_device *ndev) +{ + netif_carrier_off(ndev); + qtnf_virtual_intf_cleanup(ndev); + qtnf_netdev_updown(ndev, 0); + return 0; +} + +/* Netdev handler for data transmission. + */ +static int +qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct qtnf_vif *vif; + struct qtnf_wmac *mac; + + vif = qtnf_netdev_get_priv(ndev); + + if (unlikely(skb->dev != ndev)) { + pr_err_ratelimited("invalid skb->dev"); + dev_kfree_skb_any(skb); + return 0; + } + + if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) { + pr_err_ratelimited("%s: VIF not initialized\n", ndev->name); + dev_kfree_skb_any(skb); + return 0; + } + + mac = vif->mac; + if (unlikely(!mac)) { + pr_err_ratelimited("%s: NULL mac pointer", ndev->name); + dev_kfree_skb_any(skb); + return 0; + } + + if (!skb->len || (skb->len > ETH_FRAME_LEN)) { + pr_err_ratelimited("%s: invalid skb len %d\n", ndev->name, + skb->len); + dev_kfree_skb_any(skb); + ndev->stats.tx_dropped++; + return 0; + } + + /* tx path is enabled: reset vif timeout */ + vif->cons_tx_timeout_cnt = 0; + + return qtnf_bus_data_tx(mac->bus, skb); +} + +/* Netdev handler for getting stats. + */ +static struct net_device_stats *qtnf_netdev_get_stats(struct net_device *dev) +{ + return &dev->stats; +} + +/* Netdev handler for transmission timeout. + */ +static void qtnf_netdev_tx_timeout(struct net_device *ndev) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + struct qtnf_wmac *mac; + struct qtnf_bus *bus; + + if (unlikely(!vif || !vif->mac || !vif->mac->bus)) + return; + + mac = vif->mac; + bus = mac->bus; + + pr_warn("VIF%u.%u: Tx timeout- %lu\n", mac->macid, vif->vifid, jiffies); + + qtnf_bus_data_tx_timeout(bus, ndev); + ndev->stats.tx_errors++; + + if (++vif->cons_tx_timeout_cnt > QTNF_TX_TIMEOUT_TRSHLD) { + pr_err("Tx timeout threshold exceeded !\n"); + pr_err("schedule interface %s reset !\n", netdev_name(ndev)); + queue_work(bus->workqueue, &vif->reset_work); + } +} + +/* Network device ops handlers */ +const struct net_device_ops qtnf_netdev_ops = { + .ndo_open = qtnf_netdev_open, + .ndo_stop = qtnf_netdev_close, + .ndo_start_xmit = qtnf_netdev_hard_start_xmit, + .ndo_tx_timeout = qtnf_netdev_tx_timeout, + .ndo_get_stats = qtnf_netdev_get_stats, +}; + +static int qtnf_mac_init_single_band(struct wiphy *wiphy, + struct qtnf_wmac *mac, + enum nl80211_band band) +{ + int ret; + + wiphy->bands[band] = kzalloc(sizeof(*wiphy->bands[band]), GFP_KERNEL); + if (!wiphy->bands[band]) + return -ENOMEM; + + wiphy->bands[band]->band = band; + + ret = qtnf_cmd_get_mac_chan_info(mac, wiphy->bands[band]); + if (ret) { + pr_err("MAC%u: band %u: failed to get chans info: %d\n", + mac->macid, band, ret); + return ret; + } + + qtnf_band_init_rates(wiphy->bands[band]); + qtnf_band_setup_htvht_caps(&mac->macinfo, wiphy->bands[band]); + + return 0; +} + +static int qtnf_mac_init_bands(struct qtnf_wmac *mac) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + int ret = 0; + + if (mac->macinfo.bands_cap & QLINK_BAND_2GHZ) { + ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_2GHZ); + if (ret) + goto out; + } + + if (mac->macinfo.bands_cap & QLINK_BAND_5GHZ) { + ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_5GHZ); + if (ret) + goto out; + } + + if (mac->macinfo.bands_cap & QLINK_BAND_60GHZ) + ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_60GHZ); + +out: + return ret; +} + +struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac) +{ + struct qtnf_vif *vif; + int i; + + for (i = 0; i < QTNF_MAX_INTF; i++) { + vif = &mac->iflist[i]; + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) + return vif; + } + + return NULL; +} + +struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac) +{ + struct qtnf_vif *vif; + + vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX]; + + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) + return NULL; + + return vif; +} + +static void qtnf_vif_reset_handler(struct work_struct *work) +{ + struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work); + + rtnl_lock(); + + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) { + rtnl_unlock(); + return; + } + + /* stop tx completely */ + netif_tx_stop_all_queues(vif->netdev); + if (netif_carrier_ok(vif->netdev)) + netif_carrier_off(vif->netdev); + + qtnf_cfg80211_vif_reset(vif); + + rtnl_unlock(); +} + +static void qtnf_mac_init_primary_intf(struct qtnf_wmac *mac) +{ + struct qtnf_vif *vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX]; + + vif->wdev.iftype = NL80211_IFTYPE_AP; + vif->bss_priority = QTNF_DEF_BSS_PRIORITY; + vif->wdev.wiphy = priv_to_wiphy(mac); + INIT_WORK(&vif->reset_work, qtnf_vif_reset_handler); + vif->cons_tx_timeout_cnt = 0; +} + +static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, + unsigned int macid) +{ + struct wiphy *wiphy; + struct qtnf_wmac *mac; + unsigned int i; + + wiphy = qtnf_wiphy_allocate(bus); + if (!wiphy) + return ERR_PTR(-ENOMEM); + + mac = wiphy_priv(wiphy); + + mac->macid = macid; + mac->bus = bus; + + for (i = 0; i < QTNF_MAX_INTF; i++) { + memset(&mac->iflist[i], 0, sizeof(struct qtnf_vif)); + mac->iflist[i].wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + mac->iflist[i].mac = mac; + mac->iflist[i].vifid = i; + qtnf_sta_list_init(&mac->iflist[i].sta_list); + } + + qtnf_mac_init_primary_intf(mac); + bus->mac[macid] = mac; + + return mac; +} + +int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif, + const char *name, unsigned char name_assign_type, + enum nl80211_iftype iftype) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + struct net_device *dev; + void *qdev_vif; + int ret; + + dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name, + name_assign_type, ether_setup, 1, 1); + if (!dev) { + memset(&vif->wdev, 0, sizeof(vif->wdev)); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return -ENOMEM; + } + + vif->netdev = dev; + + dev->netdev_ops = &qtnf_netdev_ops; + dev->needs_free_netdev = true; + dev_net_set(dev, wiphy_net(wiphy)); + dev->ieee80211_ptr = &vif->wdev; + dev->ieee80211_ptr->iftype = iftype; + ether_addr_copy(dev->dev_addr, vif->mac_addr); + SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = QTNF_DEF_WDOG_TIMEOUT; + dev->tx_queue_len = 100; + + qdev_vif = netdev_priv(dev); + *((void **)qdev_vif) = vif; + + SET_NETDEV_DEV(dev, mac->bus->dev); + + ret = register_netdevice(dev); + if (ret) { + free_netdev(dev); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + } + + return ret; +} + +static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid) +{ + struct qtnf_wmac *mac; + struct wiphy *wiphy; + struct qtnf_vif *vif; + unsigned int i; + enum nl80211_band band; + + mac = bus->mac[macid]; + + if (!mac) + return; + + wiphy = priv_to_wiphy(mac); + + for (i = 0; i < QTNF_MAX_INTF; i++) { + vif = &mac->iflist[i]; + rtnl_lock(); + if (vif->netdev && + vif->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) { + qtnf_virtual_intf_cleanup(vif->netdev); + qtnf_del_virtual_intf(wiphy, &vif->wdev); + } + rtnl_unlock(); + qtnf_sta_list_free(&vif->sta_list); + } + + if (mac->wiphy_registered) + wiphy_unregister(wiphy); + + for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; ++band) { + if (!wiphy->bands[band]) + continue; + + kfree(wiphy->bands[band]->channels); + wiphy->bands[band]->n_channels = 0; + + kfree(wiphy->bands[band]); + wiphy->bands[band] = NULL; + } + + kfree(mac->macinfo.limits); + kfree(wiphy->iface_combinations); + wiphy_free(wiphy); + bus->mac[macid] = NULL; +} + +static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid) +{ + struct qtnf_wmac *mac; + struct qtnf_vif *vif; + int ret; + + if (!(bus->hw_info.mac_bitmap & BIT(macid))) { + pr_info("MAC%u is not active in FW\n", macid); + return 0; + } + + mac = qtnf_core_mac_alloc(bus, macid); + if (IS_ERR(mac)) { + pr_err("MAC%u allocation failed\n", macid); + return PTR_ERR(mac); + } + + ret = qtnf_cmd_get_mac_info(mac); + if (ret) { + pr_err("MAC%u: failed to get info\n", macid); + goto error; + } + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not ready\n", macid); + ret = -EFAULT; + goto error; + } + + ret = qtnf_cmd_send_add_intf(vif, NL80211_IFTYPE_AP, vif->mac_addr); + if (ret) { + pr_err("MAC%u: failed to add VIF\n", macid); + goto error; + } + + ret = qtnf_cmd_send_get_phy_params(mac); + if (ret) { + pr_err("MAC%u: failed to get PHY settings\n", macid); + goto error; + } + + ret = qtnf_mac_init_bands(mac); + if (ret) { + pr_err("MAC%u: failed to init bands\n", macid); + goto error; + } + + ret = qtnf_wiphy_register(&bus->hw_info, mac); + if (ret) { + pr_err("MAC%u: wiphy registration failed\n", macid); + goto error; + } + + mac->wiphy_registered = 1; + + rtnl_lock(); + + ret = qtnf_core_net_attach(mac, vif, "wlan%d", NET_NAME_ENUM, + NL80211_IFTYPE_AP); + rtnl_unlock(); + + if (ret) { + pr_err("MAC%u: failed to attach netdev\n", macid); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + vif->netdev = NULL; + goto error; + } + + pr_debug("MAC%u initialized\n", macid); + + return 0; + +error: + qtnf_core_mac_detach(bus, macid); + return ret; +} + +int qtnf_core_attach(struct qtnf_bus *bus) +{ + unsigned int i; + int ret; + + qtnf_trans_init(bus); + + bus->fw_state = QTNF_FW_STATE_BOOT_DONE; + qtnf_bus_data_rx_start(bus); + + bus->workqueue = alloc_ordered_workqueue("QTNF_BUS", 0); + if (!bus->workqueue) { + pr_err("failed to alloc main workqueue\n"); + ret = -ENOMEM; + goto error; + } + + INIT_WORK(&bus->event_work, qtnf_event_work_handler); + + ret = qtnf_cmd_send_init_fw(bus); + if (ret) { + pr_err("failed to init FW: %d\n", ret); + goto error; + } + + bus->fw_state = QTNF_FW_STATE_ACTIVE; + + ret = qtnf_cmd_get_hw_info(bus); + if (ret) { + pr_err("failed to get HW info: %d\n", ret); + goto error; + } + + if (bus->hw_info.ql_proto_ver != QLINK_PROTO_VER) { + pr_err("qlink version mismatch %u != %u\n", + QLINK_PROTO_VER, bus->hw_info.ql_proto_ver); + ret = -EPROTONOSUPPORT; + goto error; + } + + if (bus->hw_info.num_mac > QTNF_MAX_MAC) { + pr_err("no support for number of MACs=%u\n", + bus->hw_info.num_mac); + ret = -ERANGE; + goto error; + } + + for (i = 0; i < bus->hw_info.num_mac; i++) { + ret = qtnf_core_mac_attach(bus, i); + + if (ret) { + pr_err("MAC%u: attach failed: %d\n", i, ret); + goto error; + } + } + + return 0; + +error: + qtnf_core_detach(bus); + + return ret; +} +EXPORT_SYMBOL_GPL(qtnf_core_attach); + +void qtnf_core_detach(struct qtnf_bus *bus) +{ + unsigned int macid; + + qtnf_bus_data_rx_stop(bus); + + for (macid = 0; macid < QTNF_MAX_MAC; macid++) + qtnf_core_mac_detach(bus, macid); + + if (bus->fw_state == QTNF_FW_STATE_ACTIVE) + qtnf_cmd_send_deinit_fw(bus); + + bus->fw_state = QTNF_FW_STATE_DEAD; + + if (bus->workqueue) { + flush_workqueue(bus->workqueue); + destroy_workqueue(bus->workqueue); + } + + qtnf_trans_free(bus); +} +EXPORT_SYMBOL_GPL(qtnf_core_detach); + +static inline int qtnf_is_frame_meta_magic_valid(struct qtnf_frame_meta_info *m) +{ + return m->magic_s == 0xAB && m->magic_e == 0xBA; +} + +struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_frame_meta_info *meta; + struct net_device *ndev = NULL; + struct qtnf_wmac *mac; + struct qtnf_vif *vif; + + meta = (struct qtnf_frame_meta_info *) + (skb_tail_pointer(skb) - sizeof(*meta)); + + if (unlikely(!qtnf_is_frame_meta_magic_valid(meta))) { + pr_err_ratelimited("invalid magic 0x%x:0x%x\n", + meta->magic_s, meta->magic_e); + goto out; + } + + if (unlikely(meta->macid >= QTNF_MAX_MAC)) { + pr_err_ratelimited("invalid mac(%u)\n", meta->macid); + goto out; + } + + if (unlikely(meta->ifidx >= QTNF_MAX_INTF)) { + pr_err_ratelimited("invalid vif(%u)\n", meta->ifidx); + goto out; + } + + mac = bus->mac[meta->macid]; + + if (unlikely(!mac)) { + pr_err_ratelimited("mac(%d) does not exist\n", meta->macid); + goto out; + } + + vif = &mac->iflist[meta->ifidx]; + + if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) { + pr_err_ratelimited("vif(%u) does not exists\n", meta->ifidx); + goto out; + } + + ndev = vif->netdev; + + if (unlikely(!ndev)) { + pr_err_ratelimited("netdev for wlan%u.%u does not exists\n", + meta->macid, meta->ifidx); + goto out; + } + + __skb_trim(skb, skb->len - sizeof(*meta)); + +out: + return ndev; +} +EXPORT_SYMBOL_GPL(qtnf_classify_skb); + +MODULE_AUTHOR("Quantenna Communications"); +MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h new file mode 100644 index 000000000000..a616434281cf --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_CORE_H_ +#define _QTN_FMAC_CORE_H_ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/semaphore.h> +#include <linux/ip.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> +#include <net/sock.h> +#include <net/lib80211.h> +#include <net/cfg80211.h> +#include <linux/vmalloc.h> +#include <linux/firmware.h> +#include <linux/ctype.h> +#include <linux/workqueue.h> +#include <linux/slab.h> + +#include "qlink.h" +#include "trans.h" + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#define QTNF_MAX_SSID_LIST_LENGTH 2 +#define QTNF_MAX_VSIE_LEN 255 +#define QTNF_MAX_ALPHA_LEN 2 +#define QTNF_MAX_INTF 8 +#define QTNF_MAX_EVENT_QUEUE_LEN 255 +#define QTNF_DEFAULT_BG_SCAN_PERIOD 300 +#define QTNF_MAX_BG_SCAN_PERIOD 0xffff + +#define QTNF_DEF_BSS_PRIORITY 0 +#define QTNF_DEF_WDOG_TIMEOUT 5 +#define QTNF_TX_TIMEOUT_TRSHLD 100 + +#define QTNF_STATE_AP_CONFIG BIT(2) +#define QTNF_STATE_AP_START BIT(1) + +extern const struct net_device_ops qtnf_netdev_ops; +struct qtnf_bus; +struct qtnf_vif; + +struct qtnf_bss_config { + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bssid[ETH_ALEN]; + size_t ssid_len; + u8 dtim; + u16 bcn_period; + u16 auth_type; + bool privacy; + enum nl80211_mfp mfp; + struct cfg80211_chan_def chandef; + struct cfg80211_crypto_settings crypto; + u16 bg_scan_period; + u32 connect_flags; +}; + +struct qtnf_sta_node { + struct list_head list; + u8 mac_addr[ETH_ALEN]; +}; + +struct qtnf_sta_list { + struct list_head head; + atomic_t size; +}; + +enum qtnf_sta_state { + QTNF_STA_DISCONNECTED, + QTNF_STA_CONNECTING, + QTNF_STA_CONNECTED +}; + +struct qtnf_vif { + struct wireless_dev wdev; + u8 vifid; + u8 bss_priority; + u8 bss_status; + enum qtnf_sta_state sta_state; + u16 mgmt_frames_bitmask; + struct net_device *netdev; + struct qtnf_wmac *mac; + u8 mac_addr[ETH_ALEN]; + struct work_struct reset_work; + struct qtnf_bss_config bss_cfg; + struct qtnf_sta_list sta_list; + unsigned long cons_tx_timeout_cnt; +}; + +struct qtnf_mac_info { + u8 bands_cap; + u8 phymode_cap; + u8 dev_mac[ETH_ALEN]; + u8 num_tx_chain; + u8 num_rx_chain; + u16 max_ap_assoc_sta; + u32 frag_thr; + u32 rts_thr; + u8 lretry_limit; + u8 sretry_limit; + u8 coverage_class; + u8 radar_detect_widths; + struct ieee80211_ht_cap ht_cap; + struct ieee80211_vht_cap vht_cap; + struct ieee80211_iface_limit *limits; + size_t n_limits; +}; + +struct qtnf_wmac { + u8 macid; + u8 wiphy_registered; + u8 macaddr[ETH_ALEN]; + struct qtnf_bus *bus; + struct qtnf_mac_info macinfo; + struct qtnf_vif iflist[QTNF_MAX_INTF]; + struct cfg80211_scan_request *scan_req; +}; + +struct qtnf_hw_info { + u8 num_mac; + u8 mac_bitmap; + u8 alpha2_code[QTNF_MAX_ALPHA_LEN]; + u32 fw_ver; + u16 ql_proto_ver; + u8 total_tx_chain; + u8 total_rx_chain; + u32 hw_capab; +}; + +struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac); +struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac); +struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus); +int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv, + const char *name, unsigned char name_assign_type, + enum nl80211_iftype iftype); +void qtnf_main_work_queue(struct work_struct *work); +int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed); +int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac); + +struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid); +struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb); +struct net_device *qtnf_classify_skb_no_mbss(struct qtnf_bus *bus, + struct sk_buff *skb); + +void qtnf_virtual_intf_cleanup(struct net_device *ndev); + +void qtnf_netdev_updown(struct net_device *ndev, bool up); + +static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev) +{ + return *((void **)netdev_priv(dev)); +} + +#endif /* _QTN_FMAC_CORE_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/debug.c b/drivers/net/wireless/quantenna/qtnfmac/debug.c new file mode 100644 index 000000000000..9f826b9ef5d9 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/debug.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include "debug.h" + +#undef pr_fmt +#define pr_fmt(fmt) "qtnfmac dbg: %s: " fmt, __func__ + +void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name) +{ + bus->dbg_dir = debugfs_create_dir(name, NULL); + + if (IS_ERR_OR_NULL(bus->dbg_dir)) { + pr_warn("failed to create debugfs root dir\n"); + bus->dbg_dir = NULL; + } +} + +void qtnf_debugfs_remove(struct qtnf_bus *bus) +{ + debugfs_remove_recursive(bus->dbg_dir); + bus->dbg_dir = NULL; +} + +void qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name, + int (*fn)(struct seq_file *seq, void *data)) +{ + struct dentry *entry; + + entry = debugfs_create_devm_seqfile(bus->dev, name, bus->dbg_dir, fn); + if (IS_ERR_OR_NULL(entry)) + pr_warn("failed to add entry (%s)\n", name); +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/debug.h b/drivers/net/wireless/quantenna/qtnfmac/debug.h new file mode 100644 index 000000000000..d6dd12b5d434 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/debug.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_DEBUG_H_ +#define _QTN_FMAC_DEBUG_H_ + +#include <linux/debugfs.h> + +#include "core.h" +#include "bus.h" + +#ifdef CONFIG_DEBUG_FS + +void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name); +void qtnf_debugfs_remove(struct qtnf_bus *bus); +void qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name, + int (*fn)(struct seq_file *seq, void *data)); + +#else + +static inline void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name) +{ +} + +static inline void qtnf_debugfs_remove(struct qtnf_bus *bus) +{ +} + +static inline void +qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name, + int (*fn)(struct seq_file *seq, void *data)) +{ +} + +#endif /* CONFIG_DEBUG_FS */ + +#endif /* _QTN_FMAC_DEBUG_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c new file mode 100644 index 000000000000..9b61e9a83670 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "cfg80211.h" +#include "core.h" +#include "qlink.h" +#include "bus.h" +#include "trans.h" +#include "util.h" +#include "event.h" + +static int +qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, + const struct qlink_event_sta_assoc *sta_assoc, + u16 len) +{ + const u8 *sta_addr; + u16 frame_control; + struct station_info sinfo = { 0 }; + size_t payload_len; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + if (unlikely(len < sizeof(*sta_assoc))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + mac->macid, vif->vifid, len, sizeof(*sta_assoc)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_AP) { + pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: STA_ASSOC event when AP is not started\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + sta_addr = sta_assoc->sta_addr; + frame_control = le16_to_cpu(sta_assoc->frame_control); + + pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr, + frame_control); + + qtnf_sta_list_add(&vif->sta_list, sta_addr); + + sinfo.assoc_req_ies = NULL; + sinfo.assoc_req_ies_len = 0; + + payload_len = len - sizeof(*sta_assoc); + tlv = (struct qlink_tlv_hdr *)sta_assoc->ies; + + while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + + if (tlv_full_len > payload_len) { + pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n", + mac->macid, vif->vifid, tlv_type, + tlv_value_len); + return -EINVAL; + } + + if (tlv_type == QTN_TLV_ID_IE_SET) { + sinfo.assoc_req_ies = tlv->val; + sinfo.assoc_req_ies_len = tlv_value_len; + } + + payload_len -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_len) { + pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n", + mac->macid, vif->vifid, payload_len); + return -EINVAL; + } + + cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, &sinfo, + GFP_KERNEL); + + return 0; +} + +static int +qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif, + const struct qlink_event_sta_deauth *sta_deauth, + u16 len) +{ + const u8 *sta_addr; + u16 reason; + + if (unlikely(len < sizeof(*sta_deauth))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + mac->macid, vif->vifid, len, + sizeof(struct qlink_event_sta_deauth)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_AP) { + pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: STA_DEAUTH event when AP is not started\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + sta_addr = sta_deauth->sta_addr; + reason = le16_to_cpu(sta_deauth->reason); + + pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid, + sta_addr, reason); + + if (qtnf_sta_list_del(&vif->sta_list, sta_addr)) + cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr, + GFP_KERNEL); + + return 0; +} + +static int +qtnf_event_handle_bss_join(struct qtnf_vif *vif, + const struct qlink_event_bss_join *join_info, + u16 len) +{ + if (unlikely(len < sizeof(*join_info))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, + sizeof(struct qlink_event_bss_join)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { + pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + if (vif->sta_state != QTNF_STA_CONNECTING) { + pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid, + join_info->bssid); + + cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL, + 0, le16_to_cpu(join_info->status), GFP_KERNEL); + + if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) { + vif->sta_state = QTNF_STA_CONNECTED; + netif_carrier_on(vif->netdev); + } else { + vif->sta_state = QTNF_STA_DISCONNECTED; + } + + return 0; +} + +static int +qtnf_event_handle_bss_leave(struct qtnf_vif *vif, + const struct qlink_event_bss_leave *leave_info, + u16 len) +{ + if (unlikely(len < sizeof(*leave_info))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, + sizeof(struct qlink_event_bss_leave)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { + pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + if (vif->sta_state != QTNF_STA_CONNECTED) { + pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); + + cfg80211_disconnected(vif->netdev, leave_info->reason, NULL, 0, 0, + GFP_KERNEL); + + vif->sta_state = QTNF_STA_DISCONNECTED; + netif_carrier_off(vif->netdev); + + return 0; +} + +static int +qtnf_event_handle_mgmt_received(struct qtnf_vif *vif, + const struct qlink_event_rxmgmt *rxmgmt, + u16 len) +{ + const size_t min_len = sizeof(*rxmgmt) + + sizeof(struct ieee80211_hdr_3addr); + const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data; + const u16 frame_len = len - sizeof(*rxmgmt); + enum nl80211_rxmgmt_flags flags = 0; + + if (unlikely(len < min_len)) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, min_len); + return -EINVAL; + } + + if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED) + flags |= NL80211_RXMGMT_FLAG_ANSWERED; + + pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len, + le16_to_cpu(frame->frame_control), frame->addr2); + + cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), + le32_to_cpu(rxmgmt->sig_dbm), rxmgmt->frame_data, + frame_len, flags); + + return 0; +} + +static int +qtnf_event_handle_scan_results(struct qtnf_vif *vif, + const struct qlink_event_scan_result *sr, + u16 len) +{ + struct cfg80211_bss *bss; + struct ieee80211_channel *channel; + struct wiphy *wiphy = priv_to_wiphy(vif->mac); + enum cfg80211_bss_frame_type frame_type; + size_t payload_len; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + const u8 *ies = NULL; + size_t ies_len = 0; + + if (len < sizeof(*sr)) { + pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid, + vif->vifid); + return -EINVAL; + } + + channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq)); + if (!channel) { + pr_err("VIF%u.%u: channel at %u MHz not found\n", + vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq)); + return -EINVAL; + } + + switch (sr->frame_type) { + case QLINK_BSS_FTYPE_BEACON: + frame_type = CFG80211_BSS_FTYPE_BEACON; + break; + case QLINK_BSS_FTYPE_PRESP: + frame_type = CFG80211_BSS_FTYPE_PRESP; + break; + default: + frame_type = CFG80211_BSS_FTYPE_UNKNOWN; + } + + payload_len = len - sizeof(*sr); + tlv = (struct qlink_tlv_hdr *)sr->payload; + + while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + + if (tlv_full_len > payload_len) { + pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n", + vif->mac->macid, vif->vifid, tlv_type, + tlv_value_len); + return -EINVAL; + } + + if (tlv_type == QTN_TLV_ID_IE_SET) { + ies = tlv->val; + ies_len = tlv_value_len; + } + + payload_len -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_len) { + pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n", + vif->mac->macid, vif->vifid, payload_len); + return -EINVAL; + } + + bss = cfg80211_inform_bss(wiphy, channel, frame_type, + sr->bssid, get_unaligned_le64(&sr->tsf), + le16_to_cpu(sr->capab), + le16_to_cpu(sr->bintval), ies, ies_len, + sr->signal, GFP_KERNEL); + if (!bss) + return -ENOMEM; + + cfg80211_put_bss(wiphy, bss); + + return 0; +} + +static int +qtnf_event_handle_scan_complete(struct qtnf_wmac *mac, + const struct qlink_event_scan_complete *status, + u16 len) +{ + if (len < sizeof(*status)) { + pr_err("MAC%u: payload is too short\n", mac->macid); + return -EINVAL; + } + + qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED); + + return 0; +} + +static int qtnf_event_parse(struct qtnf_wmac *mac, + const struct sk_buff *event_skb) +{ + const struct qlink_event *event; + struct qtnf_vif *vif = NULL; + int ret = -1; + u16 event_id; + u16 event_len; + + event = (const struct qlink_event *)event_skb->data; + event_id = le16_to_cpu(event->event_id); + event_len = le16_to_cpu(event->mhdr.len); + + if (likely(event->vifid < QTNF_MAX_INTF)) { + vif = &mac->iflist[event->vifid]; + } else { + pr_err("invalid vif(%u)\n", event->vifid); + return -EINVAL; + } + + switch (event_id) { + case QLINK_EVENT_STA_ASSOCIATED: + ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_STA_DEAUTH: + ret = qtnf_event_handle_sta_deauth(mac, vif, + (const void *)event, + event_len); + break; + case QLINK_EVENT_MGMT_RECEIVED: + ret = qtnf_event_handle_mgmt_received(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_SCAN_RESULTS: + ret = qtnf_event_handle_scan_results(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_SCAN_COMPLETE: + ret = qtnf_event_handle_scan_complete(mac, (const void *)event, + event_len); + break; + case QLINK_EVENT_BSS_JOIN: + ret = qtnf_event_handle_bss_join(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_BSS_LEAVE: + ret = qtnf_event_handle_bss_leave(vif, (const void *)event, + event_len); + break; + default: + pr_warn("unknown event type: %x\n", event_id); + break; + } + + return ret; +} + +static int qtnf_event_process_skb(struct qtnf_bus *bus, + const struct sk_buff *skb) +{ + const struct qlink_event *event; + struct qtnf_wmac *mac; + int res; + + if (unlikely(!skb || skb->len < sizeof(*event))) { + pr_err("invalid event buffer\n"); + return -EINVAL; + } + + event = (struct qlink_event *)skb->data; + + mac = qtnf_core_get_mac(bus, event->macid); + + pr_debug("new event id:%x len:%u mac:%u vif:%u\n", + le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len), + event->macid, event->vifid); + + if (unlikely(!mac)) + return -ENXIO; + + qtnf_bus_lock(bus); + res = qtnf_event_parse(mac, skb); + qtnf_bus_unlock(bus); + + return res; +} + +void qtnf_event_work_handler(struct work_struct *work) +{ + struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work); + struct sk_buff_head *event_queue = &bus->trans.event_queue; + struct sk_buff *current_event_skb = skb_dequeue(event_queue); + + while (current_event_skb) { + qtnf_event_process_skb(bus, current_event_skb); + dev_kfree_skb_any(current_event_skb); + current_event_skb = skb_dequeue(event_queue); + } +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.h b/drivers/net/wireless/quantenna/qtnfmac/event.h new file mode 100644 index 000000000000..ae759b602c2a --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/event.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_EVENT_H_ +#define _QTN_FMAC_EVENT_H_ + +#include <linux/kernel.h> +#include <linux/module.h> + +#include "qlink.h" + +void qtnf_event_work_handler(struct work_struct *work); + +#endif /* _QTN_FMAC_EVENT_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c new file mode 100644 index 000000000000..7fc4f0d6a9ad --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -0,0 +1,1378 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/completion.h> +#include <linux/crc32.h> +#include <linux/spinlock.h> + +#include "qtn_hw_ids.h" +#include "pcie_bus_priv.h" +#include "core.h" +#include "bus.h" +#include "debug.h" + +static bool use_msi = true; +module_param(use_msi, bool, 0644); +MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt"); + +static unsigned int tx_bd_size_param = 256; +module_param(tx_bd_size_param, uint, 0644); +MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size"); + +static unsigned int rx_bd_size_param = 256; +module_param(rx_bd_size_param, uint, 0644); +MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size"); + +static unsigned int rx_bd_reserved_param = 16; +module_param(rx_bd_reserved_param, uint, 0644); +MODULE_PARM_DESC(rx_bd_reserved_param, "Reserved RX descriptors"); + +static u8 flashboot = 1; +module_param(flashboot, byte, 0644); +MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS"); + +#define DRV_NAME "qtnfmac_pearl_pcie" + +static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) +{ + writel(val, basereg); + + /* flush posted write */ + readl(basereg); +} + +static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + writel(0x0, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_en_txdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static int qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) +{ + struct pci_dev *pdev = priv->pdev; + + /* fall back to legacy INTx interrupts by default */ + priv->msi_enabled = 0; + + /* check if MSI capability is available */ + if (use_msi) { + if (!pci_enable_msi(pdev)) { + pr_debug("MSI interrupt enabled\n"); + priv->msi_enabled = 1; + } else { + pr_warn("failed to enable MSI interrupts"); + } + } + + if (!priv->msi_enabled) { + pr_warn("legacy PCIE interrupts enabled\n"); + pci_intx(pdev, 1); + } + + return 0; +} + +static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv) +{ + void __iomem *reg = priv->sysctl_bar + PEARL_PCIE_CFG0_OFFSET; + u32 cfg; + + cfg = readl(reg); + cfg &= ~PEARL_ASSERT_INTX; + qtnf_non_posted_write(cfg, reg); +} + +static void qtnf_ipc_gen_ep_int(void *arg) +{ + const struct qtnf_pcie_bus_priv *priv = arg; + const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ); + void __iomem *reg = priv->sysctl_bar + + QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; + + qtnf_non_posted_write(data, reg); +} + +static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) +{ + void __iomem *vaddr; + dma_addr_t busaddr; + size_t len; + int ret; + + ret = pcim_iomap_regions(priv->pdev, 1 << index, DRV_NAME); + if (ret) + return IOMEM_ERR_PTR(ret); + + busaddr = pci_resource_start(priv->pdev, index); + vaddr = pcim_iomap_table(priv->pdev)[index]; + len = pci_resource_len(priv->pdev, index); + + pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", + index, vaddr, &busaddr, (int)len); + + return vaddr; +} + +static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) +{ + struct qtnf_pcie_bus_priv *priv = arg; + struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); + struct sk_buff *skb; + + if (unlikely(len == 0)) { + pr_warn("zero length packet received\n"); + return; + } + + skb = __dev_alloc_skb(len, GFP_KERNEL); + + if (unlikely(!skb)) { + pr_err("failed to allocate skb\n"); + return; + } + + skb_put_data(skb, buf, len); + + qtnf_trans_handle_rx_ctl_packet(bus, skb); +} + +static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv) +{ + struct qtnf_shm_ipc_region __iomem *ipc_tx_reg; + struct qtnf_shm_ipc_region __iomem *ipc_rx_reg; + const struct qtnf_shm_ipc_int ipc_int = { qtnf_ipc_gen_ep_int, priv }; + const struct qtnf_shm_ipc_rx_callback rx_callback = { + qtnf_pcie_control_rx_callback, priv }; + + ipc_tx_reg = &priv->bda->bda_shm_reg1; + ipc_rx_reg = &priv->bda->bda_shm_reg2; + + qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, + ipc_tx_reg, priv->workqueue, + &ipc_int, &rx_callback); + qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, + ipc_rx_reg, priv->workqueue, + &ipc_int, &rx_callback); + + return 0; +} + +static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) +{ + qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); + qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); +} + +static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) +{ + int ret = -ENOMEM; + + priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); + if (IS_ERR_OR_NULL(priv->sysctl_bar)) { + pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); + return ret; + } + + priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR); + if (IS_ERR_OR_NULL(priv->dmareg_bar)) { + pr_err("failed to map BAR%u\n", QTN_DMA_BAR); + return ret; + } + + priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR); + if (IS_ERR_OR_NULL(priv->epmem_bar)) { + pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); + return ret; + } + + priv->pcie_reg_base = priv->dmareg_bar; + priv->bda = priv->epmem_bar; + writel(priv->msi_enabled, &priv->bda->bda_rc_msi_enabled); + + return 0; +} + +static int +qtnf_pcie_init_dma_mask(struct qtnf_pcie_bus_priv *priv, u64 dma_mask) +{ + int ret; + + ret = dma_supported(&priv->pdev->dev, dma_mask); + if (!ret) { + pr_err("DMA mask %llu not supported\n", dma_mask); + return ret; + } + + ret = pci_set_dma_mask(priv->pdev, dma_mask); + if (ret) { + pr_err("failed to set DMA mask %llu\n", dma_mask); + return ret; + } + + ret = pci_set_consistent_dma_mask(priv->pdev, dma_mask); + if (ret) { + pr_err("failed to set consistent DMA mask %llu\n", dma_mask); + return ret; + } + + return ret; +} + +static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) +{ + struct pci_dev *pdev = priv->pdev; + struct pci_dev *parent; + int mps_p, mps_o, mps_m, mps; + int ret; + + /* current mps */ + mps_o = pcie_get_mps(pdev); + + /* maximum supported mps */ + mps_m = 128 << pdev->pcie_mpss; + + /* suggested new mps value */ + mps = mps_m; + + if (pdev->bus && pdev->bus->self) { + /* parent (bus) mps */ + parent = pdev->bus->self; + + if (pci_is_pcie(parent)) { + mps_p = pcie_get_mps(parent); + mps = min(mps_m, mps_p); + } + } + + ret = pcie_set_mps(pdev, mps); + if (ret) { + pr_err("failed to set mps to %d, keep using current %d\n", + mps, mps_o); + priv->mps = mps_o; + return; + } + + pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m); + priv->mps = mps; +} + +static int qtnf_is_state(__le32 __iomem *reg, u32 state) +{ + u32 s = readl(reg); + + return s & state; +} + +static void qtnf_set_state(__le32 __iomem *reg, u32 state) +{ + u32 s = readl(reg); + + qtnf_non_posted_write(state | s, reg); +} + +static void qtnf_clear_state(__le32 __iomem *reg, u32 state) +{ + u32 s = readl(reg); + + qtnf_non_posted_write(s & ~state, reg); +} + +static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms) +{ + u32 timeout = 0; + + while ((qtnf_is_state(reg, state) == 0)) { + usleep_range(1000, 1200); + if (++timeout > delay_in_ms) + return -1; + } + + return 0; +} + +static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) +{ + struct sk_buff **vaddr; + int len; + + len = priv->tx_bd_num * sizeof(*priv->tx_skb) + + priv->rx_bd_num * sizeof(*priv->rx_skb); + vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL); + + if (!vaddr) + return -ENOMEM; + + priv->tx_skb = vaddr; + + vaddr += priv->tx_bd_num; + priv->rx_skb = vaddr; + + return 0; +} + +static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv) +{ + dma_addr_t paddr; + void *vaddr; + int len; + + len = priv->tx_bd_num * sizeof(struct qtnf_tx_bd) + + priv->rx_bd_num * sizeof(struct qtnf_rx_bd); + + vaddr = dmam_alloc_coherent(&priv->pdev->dev, len, &paddr, GFP_KERNEL); + if (!vaddr) + return -ENOMEM; + + /* tx bd */ + + memset(vaddr, 0, len); + + priv->bd_table_vaddr = vaddr; + priv->bd_table_paddr = paddr; + priv->bd_table_len = len; + + priv->tx_bd_vbase = vaddr; + priv->tx_bd_pbase = paddr; + + pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); + + priv->tx_bd_reclaim_start = 0; + priv->tx_bd_index = 0; + priv->tx_queue_len = 0; + + /* rx bd */ + + vaddr = ((struct qtnf_tx_bd *)vaddr) + priv->tx_bd_num; + paddr += priv->tx_bd_num * sizeof(struct qtnf_tx_bd); + + priv->rx_bd_vbase = vaddr; + priv->rx_bd_pbase = paddr; + + writel(QTN_HOST_LO32(paddr), + PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base)); + writel(QTN_HOST_HI32(paddr), + PCIE_HDP_TX_HOST_Q_BASE_H(priv->pcie_reg_base)); + writel(priv->rx_bd_num | (sizeof(struct qtnf_rx_bd)) << 16, + PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base)); + + priv->hw_txproc_wr_ptr = priv->rx_bd_num - rx_bd_reserved_param; + + writel(priv->hw_txproc_wr_ptr, + PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); + + pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); + + priv->rx_bd_index = 0; + + return 0; +} + +static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 rx_bd_index) +{ + struct qtnf_rx_bd *rxbd; + struct sk_buff *skb; + dma_addr_t paddr; + + skb = __dev_alloc_skb(SKB_BUF_SIZE + NET_IP_ALIGN, + GFP_ATOMIC); + if (!skb) { + priv->rx_skb[rx_bd_index] = NULL; + return -ENOMEM; + } + + priv->rx_skb[rx_bd_index] = skb; + + skb_reserve(skb, NET_IP_ALIGN); + + rxbd = &priv->rx_bd_vbase[rx_bd_index]; + + paddr = pci_map_single(priv->pdev, skb->data, + SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(priv->pdev, paddr)) { + pr_err("skb DMA mapping error: %pad\n", &paddr); + return -ENOMEM; + } + + writel(QTN_HOST_LO32(paddr), + PCIE_HDP_HHBM_BUF_PTR(priv->pcie_reg_base)); + writel(QTN_HOST_HI32(paddr), + PCIE_HDP_HHBM_BUF_PTR_H(priv->pcie_reg_base)); + + /* keep rx skb paddrs in rx buffer descriptors for cleanup purposes */ + rxbd->addr = cpu_to_le32(QTN_HOST_LO32(paddr)); + rxbd->addr_h = cpu_to_le32(QTN_HOST_HI32(paddr)); + + rxbd->info = 0x0; + + return 0; +} + +static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv) +{ + u16 i; + int ret = 0; + + memset(priv->rx_bd_vbase, 0x0, + priv->rx_bd_num * sizeof(struct qtnf_rx_bd)); + + for (i = 0; i < priv->rx_bd_num; i++) { + ret = skb2rbd_attach(priv, i); + if (ret) + break; + } + + return ret; +} + +/* all rx/tx activity should have ceased before calling this function */ +static void free_xfer_buffers(void *data) +{ + struct qtnf_pcie_bus_priv *priv = (struct qtnf_pcie_bus_priv *)data; + struct qtnf_rx_bd *rxbd; + dma_addr_t paddr; + int i; + + /* free rx buffers */ + for (i = 0; i < priv->rx_bd_num; i++) { + if (priv->rx_skb[i]) { + rxbd = &priv->rx_bd_vbase[i]; + paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), + le32_to_cpu(rxbd->addr)); + pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + dev_kfree_skb_any(priv->rx_skb[i]); + } + } + + /* free tx buffers */ + for (i = 0; i < priv->tx_bd_num; i++) { + if (priv->tx_skb[i]) { + dev_kfree_skb_any(priv->tx_skb[i]); + priv->tx_skb[i] = NULL; + } + } +} + +static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv) +{ + int ret; + + priv->tx_bd_num = tx_bd_size_param; + priv->rx_bd_num = rx_bd_size_param; + + ret = alloc_skb_array(priv); + if (ret) { + pr_err("failed to allocate skb array\n"); + return ret; + } + + ret = alloc_bd_table(priv); + if (ret) { + pr_err("failed to allocate bd table\n"); + return ret; + } + + ret = alloc_rx_buffers(priv); + if (ret) { + pr_err("failed to allocate rx buffers\n"); + return ret; + } + + return ret; +} + +static int qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) +{ + struct qtnf_tx_bd *txbd; + struct sk_buff *skb; + dma_addr_t paddr; + int last_sent; + int count; + int i; + + last_sent = readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) + % priv->tx_bd_num; + i = priv->tx_bd_reclaim_start; + count = 0; + + while (i != last_sent) { + skb = priv->tx_skb[i]; + if (!skb) + break; + + txbd = &priv->tx_bd_vbase[i]; + paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), + le32_to_cpu(txbd->addr)); + pci_unmap_single(priv->pdev, paddr, skb->len, PCI_DMA_TODEVICE); + + if (skb->dev) { + skb->dev->stats.tx_packets++; + skb->dev->stats.tx_bytes += skb->len; + + if (netif_queue_stopped(skb->dev)) + netif_wake_queue(skb->dev); + } + + dev_kfree_skb_any(skb); + priv->tx_skb[i] = NULL; + priv->tx_queue_len--; + count++; + + if (++i >= priv->tx_bd_num) + i = 0; + } + + priv->tx_bd_reclaim_start = i; + priv->tx_reclaim_done += count; + priv->tx_reclaim_req++; + + return count; +} + +static bool qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) +{ + if (priv->tx_queue_len >= priv->tx_bd_num - 1) { + pr_err_ratelimited("reclaim full Tx queue\n"); + qtnf_pcie_data_tx_reclaim(priv); + + if (priv->tx_queue_len >= priv->tx_bd_num - 1) { + priv->tx_full_count++; + return false; + } + } + + return true; +} + +static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + dma_addr_t txbd_paddr, skb_paddr; + struct qtnf_tx_bd *txbd; + unsigned long flags; + int len, i; + u32 info; + int ret = 0; + + spin_lock_irqsave(&priv->tx_lock, flags); + + priv->tx_done_count++; + + if (!qtnf_tx_queue_ready(priv)) { + if (skb->dev) + netif_stop_queue(skb->dev); + + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_BUSY; + } + + i = priv->tx_bd_index; + priv->tx_skb[i] = skb; + len = skb->len; + + skb_paddr = pci_map_single(priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(priv->pdev, skb_paddr)) { + pr_err("skb DMA mapping error: %pad\n", &skb_paddr); + ret = -ENOMEM; + goto tx_done; + } + + txbd = &priv->tx_bd_vbase[i]; + txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr)); + txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr)); + + info = (len & QTN_PCIE_TX_DESC_LEN_MASK) << QTN_PCIE_TX_DESC_LEN_SHIFT; + txbd->info = cpu_to_le32(info); + + /* sync up all descriptor updates before passing them to EP */ + dma_wmb(); + + /* write new TX descriptor to PCIE_RX_FIFO on EP */ + txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_tx_bd); + writel(QTN_HOST_LO32(txbd_paddr), + PCIE_HDP_HOST_WR_DESC0(priv->pcie_reg_base)); + writel(QTN_HOST_HI32(txbd_paddr), + PCIE_HDP_HOST_WR_DESC0_H(priv->pcie_reg_base)); + + if (++i >= priv->tx_bd_num) + i = 0; + + priv->tx_bd_index = i; + priv->tx_queue_len++; + +tx_done: + if (ret && skb) { + pr_err_ratelimited("drop skb\n"); + if (skb->dev) + skb->dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + } + + spin_unlock_irqrestore(&priv->tx_lock, flags); + + return NETDEV_TX_OK; +} + +static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + return qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); +} + +static irqreturn_t qtnf_interrupt(int irq, void *data) +{ + struct qtnf_bus *bus = (struct qtnf_bus *)data; + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + u32 status; + + priv->pcie_irq_count++; + status = readl(PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); + + qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in); + qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out); + + if (!(status & priv->pcie_irq_mask)) + goto irq_done; + + if (status & PCIE_HDP_INT_RX_BITS) { + priv->pcie_irq_rx_count++; + qtnf_dis_rxdone_irq(priv); + napi_schedule(&bus->mux_napi); + } + + if (status & PCIE_HDP_INT_TX_BITS) { + priv->pcie_irq_tx_count++; + qtnf_dis_txdone_irq(priv); + tasklet_hi_schedule(&priv->reclaim_tq); + } + +irq_done: + /* H/W workaround: clean all bits, not only enabled */ + qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); + + if (!priv->msi_enabled) + qtnf_deassert_intx(priv); + + return IRQ_HANDLED; +} + +static inline void hw_txproc_wr_ptr_inc(struct qtnf_pcie_bus_priv *priv) +{ + u32 index; + + index = priv->hw_txproc_wr_ptr; + + if (++index >= priv->rx_bd_num) + index = 0; + + priv->hw_txproc_wr_ptr = index; +} + +static int qtnf_rx_poll(struct napi_struct *napi, int budget) +{ + struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct net_device *ndev = NULL; + struct sk_buff *skb = NULL; + int processed = 0; + struct qtnf_rx_bd *rxbd; + dma_addr_t skb_paddr; + u32 descw; + u16 index; + int ret; + + index = priv->rx_bd_index; + rxbd = &priv->rx_bd_vbase[index]; + + descw = le32_to_cpu(rxbd->info); + + while ((descw & QTN_TXDONE_MASK) && (processed < budget)) { + skb = priv->rx_skb[index]; + + if (likely(skb)) { + skb_put(skb, QTN_GET_LEN(descw)); + + skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), + le32_to_cpu(rxbd->addr)); + pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + ndev = qtnf_classify_skb(bus, skb); + if (likely(ndev)) { + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += skb->len; + + skb->protocol = eth_type_trans(skb, ndev); + netif_receive_skb(skb); + } else { + pr_debug("drop untagged skb\n"); + bus->mux_dev.stats.rx_dropped++; + dev_kfree_skb_any(skb); + } + + processed++; + } else { + pr_err("missing rx_skb[%d]\n", index); + } + + /* attached rx buffer is passed upstream: map a new one */ + ret = skb2rbd_attach(priv, index); + if (likely(!ret)) { + if (++index >= priv->rx_bd_num) + index = 0; + + priv->rx_bd_index = index; + hw_txproc_wr_ptr_inc(priv); + + rxbd = &priv->rx_bd_vbase[index]; + descw = le32_to_cpu(rxbd->info); + } else { + pr_err("failed to allocate new rx_skb[%d]\n", index); + break; + } + + writel(priv->hw_txproc_wr_ptr, + PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); + } + + if (processed < budget) { + napi_complete(napi); + qtnf_en_rxdone_irq(priv); + } + + return processed; +} + +static void +qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + tasklet_hi_schedule(&priv->reclaim_tq); +} + +static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + qtnf_enable_hdp_irqs(priv); + napi_enable(&bus->mux_napi); +} + +static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + napi_disable(&bus->mux_napi); + qtnf_disable_hdp_irqs(priv); +} + +static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { + /* control path methods */ + .control_tx = qtnf_pcie_control_tx, + + /* data path methods */ + .data_tx = qtnf_pcie_data_tx, + .data_tx_timeout = qtnf_pcie_data_tx_timeout, + .data_rx_start = qtnf_pcie_data_rx_start, + .data_rx_stop = qtnf_pcie_data_rx_stop, +}; + +static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size, + int blk, const u8 *pblk, const u8 *fw) +{ + struct pci_dev *pdev = priv->pdev; + struct qtnf_bus *bus = pci_get_drvdata(pdev); + + struct qtnf_pcie_fw_hdr *hdr; + u8 *pdata; + + int hds = sizeof(*hdr); + struct sk_buff *skb = NULL; + int len = 0; + int ret; + + skb = __dev_alloc_skb(QTN_PCIE_FW_BUFSZ, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + skb->len = QTN_PCIE_FW_BUFSZ; + skb->dev = NULL; + + hdr = (struct qtnf_pcie_fw_hdr *)skb->data; + memcpy(hdr->boardflg, QTN_PCIE_BOARDFLG, strlen(QTN_PCIE_BOARDFLG)); + hdr->fwsize = cpu_to_le32(size); + hdr->seqnum = cpu_to_le32(blk); + + if (blk) + hdr->type = cpu_to_le32(QTN_FW_DSUB); + else + hdr->type = cpu_to_le32(QTN_FW_DBEGIN); + + pdata = skb->data + hds; + + len = QTN_PCIE_FW_BUFSZ - hds; + if (pblk >= (fw + size - len)) { + len = fw + size - pblk; + hdr->type = cpu_to_le32(QTN_FW_DEND); + } + + hdr->pktlen = cpu_to_le32(len); + memcpy(pdata, pblk, len); + hdr->crc = cpu_to_le32(~crc32(0, pdata, len)); + + ret = qtnf_pcie_data_tx(bus, skb); + + return (ret == NETDEV_TX_OK) ? len : 0; +} + +static int +qtnf_ep_fw_load(struct qtnf_pcie_bus_priv *priv, const u8 *fw, u32 fw_size) +{ + int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pcie_fw_hdr); + int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0); + const u8 *pblk = fw; + int threshold = 0; + int blk = 0; + int len; + + pr_debug("FW upload started: fw_addr=0x%p size=%d\n", fw, fw_size); + + while (blk < blk_count) { + if (++threshold > 10000) { + pr_err("FW upload failed: too many retries\n"); + return -ETIMEDOUT; + } + + len = qtnf_ep_fw_send(priv, fw_size, blk, pblk, fw); + if (len <= 0) + continue; + + if (!((blk + 1) & QTN_PCIE_FW_DLMASK) || + (blk == (blk_count - 1))) { + qtnf_set_state(&priv->bda->bda_rc_state, + QTN_RC_FW_SYNC); + if (qtnf_poll_state(&priv->bda->bda_ep_state, + QTN_EP_FW_SYNC, + QTN_FW_DL_TIMEOUT_MS)) { + pr_err("FW upload failed: SYNC timed out\n"); + return -ETIMEDOUT; + } + + qtnf_clear_state(&priv->bda->bda_ep_state, + QTN_EP_FW_SYNC); + + if (qtnf_is_state(&priv->bda->bda_ep_state, + QTN_EP_FW_RETRY)) { + if (blk == (blk_count - 1)) { + int last_round = + blk_count & QTN_PCIE_FW_DLMASK; + blk -= last_round; + pblk -= ((last_round - 1) * + blk_size + len); + } else { + blk -= QTN_PCIE_FW_DLMASK; + pblk -= QTN_PCIE_FW_DLMASK * blk_size; + } + + qtnf_clear_state(&priv->bda->bda_ep_state, + QTN_EP_FW_RETRY); + + pr_warn("FW upload retry: block #%d\n", blk); + continue; + } + + qtnf_pcie_data_tx_reclaim(priv); + } + + pblk += len; + blk++; + } + + pr_debug("FW upload completed: totally sent %d blocks\n", blk); + return 0; +} + +static void qtnf_firmware_load(const struct firmware *fw, void *context) +{ + struct qtnf_pcie_bus_priv *priv = (void *)context; + struct pci_dev *pdev = priv->pdev; + struct qtnf_bus *bus = pci_get_drvdata(pdev); + int ret; + + if (!fw) { + pr_err("failed to get firmware %s\n", bus->fwname); + goto fw_load_err; + } + + ret = qtnf_ep_fw_load(priv, fw->data, fw->size); + if (ret) { + pr_err("FW upload error\n"); + goto fw_load_err; + } + + if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, + QTN_FW_DL_TIMEOUT_MS)) { + pr_err("FW bringup timed out\n"); + goto fw_load_err; + } + + bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + pr_info("firmware is up and running\n"); + +fw_load_err: + + if (fw) + release_firmware(fw); + + complete(&bus->request_firmware_complete); +} + +static int qtnf_bringup_fw(struct qtnf_bus *bus) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct pci_dev *pdev = priv->pdev; + int ret; + u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; + + if (flashboot) + state |= QTN_RC_FW_FLASHBOOT; + + qtnf_set_state(&priv->bda->bda_rc_state, state); + + if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY, + QTN_FW_DL_TIMEOUT_MS)) { + pr_err("card is not ready\n"); + return -ETIMEDOUT; + } + + qtnf_clear_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY); + + if (flashboot) { + pr_info("Booting FW from flash\n"); + + if (!qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, + QTN_FW_DL_TIMEOUT_MS)) + bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + + return 0; + } + + pr_info("starting firmware upload: %s\n", bus->fwname); + + ret = request_firmware_nowait(THIS_MODULE, 1, bus->fwname, &pdev->dev, + GFP_KERNEL, priv, qtnf_firmware_load); + if (ret < 0) + pr_err("request_firmware_nowait error %d\n", ret); + else + ret = 1; + + return ret; +} + +static void qtnf_reclaim_tasklet_fn(unsigned long data) +{ + struct qtnf_pcie_bus_priv *priv = (void *)data; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_lock, flags); + qtnf_pcie_data_tx_reclaim(priv); + spin_unlock_irqrestore(&priv->tx_lock, flags); + qtnf_en_txdone_irq(priv); +} + +static int qtnf_dbg_mps_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%d\n", priv->mps); + + return 0; +} + +static int qtnf_dbg_msi_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%u\n", priv->msi_enabled); + + return 0; +} + +static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count); + seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count); + seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count); + + return 0; +} + +static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); + seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); + seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); + seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); + seq_printf(s, "tx_bd_reclaim_start(%u)\n", priv->tx_bd_reclaim_start); + seq_printf(s, "tx_bd_index(%u)\n", priv->tx_bd_index); + seq_printf(s, "rx_bd_index(%u)\n", priv->rx_bd_index); + seq_printf(s, "tx_queue_len(%u)\n", priv->tx_queue_len); + + return 0; +} + +static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.tx_packet_count); + seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.rx_packet_count); + seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.tx_timeout_count); + seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.rx_packet_count); + + return 0; +} + +static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct qtnf_pcie_bus_priv *pcie_priv; + struct qtnf_bus *bus; + int ret; + + bus = devm_kzalloc(&pdev->dev, + sizeof(*bus) + sizeof(*pcie_priv), GFP_KERNEL); + if (!bus) { + ret = -ENOMEM; + goto err_init; + } + + pcie_priv = get_bus_priv(bus); + + pci_set_drvdata(pdev, bus); + bus->bus_ops = &qtnf_pcie_bus_ops; + bus->dev = &pdev->dev; + bus->fw_state = QTNF_FW_STATE_RESET; + pcie_priv->pdev = pdev; + + strcpy(bus->fwname, QTN_PCI_PEARL_FW_NAME); + init_completion(&bus->request_firmware_complete); + mutex_init(&bus->bus_lock); + spin_lock_init(&pcie_priv->irq_lock); + spin_lock_init(&pcie_priv->tx_lock); + + /* init stats */ + pcie_priv->tx_full_count = 0; + pcie_priv->tx_done_count = 0; + pcie_priv->pcie_irq_count = 0; + pcie_priv->pcie_irq_rx_count = 0; + pcie_priv->pcie_irq_tx_count = 0; + pcie_priv->tx_reclaim_done = 0; + pcie_priv->tx_reclaim_req = 0; + + pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); + if (!pcie_priv->workqueue) { + pr_err("failed to alloc bus workqueue\n"); + ret = -ENODEV; + goto err_priv; + } + + if (!pci_is_pcie(pdev)) { + pr_err("device %s is not PCI Express\n", pci_name(pdev)); + ret = -EIO; + goto err_base; + } + + qtnf_tune_pcie_mps(pcie_priv); + + ret = pcim_enable_device(pdev); + if (ret) { + pr_err("failed to init PCI device %x\n", pdev->device); + goto err_base; + } else { + pr_debug("successful init of PCI device %x\n", pdev->device); + } + + pcim_pin_device(pdev); + pci_set_master(pdev); + + ret = qtnf_pcie_init_irq(pcie_priv); + if (ret < 0) { + pr_err("irq init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_memory(pcie_priv); + if (ret < 0) { + pr_err("PCIE memory init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_shm_ipc(pcie_priv); + if (ret < 0) { + pr_err("PCIE SHM IPC init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_dma_mask(pcie_priv, DMA_BIT_MASK(32)); + if (ret) { + pr_err("PCIE DMA mask init failed\n"); + goto err_base; + } + + ret = devm_add_action(&pdev->dev, free_xfer_buffers, (void *)pcie_priv); + if (ret) { + pr_err("custom release callback init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_xfer(pcie_priv); + if (ret) { + pr_err("PCIE xfer init failed\n"); + goto err_base; + } + + /* init default irq settings */ + qtnf_init_hdp_irqs(pcie_priv); + + /* start with disabled irqs */ + qtnf_disable_hdp_irqs(pcie_priv); + + ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_interrupt, 0, + "qtnf_pcie_irq", (void *)bus); + if (ret) { + pr_err("failed to request pcie irq %d\n", pdev->irq); + goto err_base; + } + + tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, + (unsigned long)pcie_priv); + init_dummy_netdev(&bus->mux_dev); + netif_napi_add(&bus->mux_dev, &bus->mux_napi, + qtnf_rx_poll, 10); + + ret = qtnf_bringup_fw(bus); + if (ret < 0) + goto err_bringup_fw; + else if (ret) + wait_for_completion(&bus->request_firmware_complete); + + if (bus->fw_state != QTNF_FW_STATE_FW_DNLD_DONE) { + pr_err("failed to start FW\n"); + goto err_bringup_fw; + } + + if (qtnf_poll_state(&pcie_priv->bda->bda_ep_state, QTN_EP_FW_QLINK_DONE, + QTN_FW_QLINK_TIMEOUT_MS)) { + pr_err("FW runtime failure\n"); + goto err_bringup_fw; + } + + ret = qtnf_core_attach(bus); + if (ret) { + pr_err("failed to attach core\n"); + goto err_bringup_fw; + } + + qtnf_debugfs_init(bus, DRV_NAME); + qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); + qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); + qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); + qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); + qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); + + return 0; + +err_bringup_fw: + netif_napi_del(&bus->mux_napi); + +err_base: + flush_workqueue(pcie_priv->workqueue); + destroy_workqueue(pcie_priv->workqueue); + +err_priv: + pci_set_drvdata(pdev, NULL); + +err_init: + return ret; +} + +static void qtnf_pcie_remove(struct pci_dev *pdev) +{ + struct qtnf_pcie_bus_priv *priv; + struct qtnf_bus *bus; + + bus = pci_get_drvdata(pdev); + if (!bus) + return; + + priv = get_bus_priv(bus); + + qtnf_core_detach(bus); + netif_napi_del(&bus->mux_napi); + + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + tasklet_kill(&priv->reclaim_tq); + + qtnf_debugfs_remove(bus); + + qtnf_pcie_free_shm_ipc(priv); +} + +#ifdef CONFIG_PM_SLEEP +static int qtnf_pcie_suspend(struct device *dev) +{ + return -EOPNOTSUPP; +} + +static int qtnf_pcie_resume(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_SLEEP +/* Power Management Hooks */ +static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend, + qtnf_pcie_resume); +#endif + +static struct pci_device_id qtnf_pcie_devid_table[] = { + { + PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table); + +static struct pci_driver qtnf_pcie_drv_data = { + .name = DRV_NAME, + .id_table = qtnf_pcie_devid_table, + .probe = qtnf_pcie_probe, + .remove = qtnf_pcie_remove, +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &qtnf_pcie_pm_ops, + }, +#endif +}; + +static int __init qtnf_pcie_register(void) +{ + pr_info("register Quantenna QSR10g FullMAC PCIE driver\n"); + return pci_register_driver(&qtnf_pcie_drv_data); +} + +static void __exit qtnf_pcie_exit(void) +{ + pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n"); + pci_unregister_driver(&qtnf_pcie_drv_data); +} + +module_init(qtnf_pcie_register); +module_exit(qtnf_pcie_exit); + +MODULE_AUTHOR("Quantenna Communications"); +MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h new file mode 100644 index 000000000000..2a897db2bd79 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_PCIE_H_ +#define _QTN_FMAC_PCIE_H_ + +#include <linux/dma-mapping.h> +#include <linux/io.h> + +#include "pcie_regs_pearl.h" +#include "pcie_ipc.h" +#include "shm_ipc.h" + +struct bus; + +struct qtnf_pcie_bus_priv { + struct pci_dev *pdev; + + /* lock for irq configuration changes */ + spinlock_t irq_lock; + + /* lock for tx operations */ + spinlock_t tx_lock; + u8 msi_enabled; + int mps; + + struct workqueue_struct *workqueue; + struct tasklet_struct reclaim_tq; + + void __iomem *sysctl_bar; + void __iomem *epmem_bar; + void __iomem *dmareg_bar; + + struct qtnf_shm_ipc shm_ipc_ep_in; + struct qtnf_shm_ipc shm_ipc_ep_out; + + struct qtnf_pcie_bda __iomem *bda; + void __iomem *pcie_reg_base; + + u16 tx_bd_num; + u16 rx_bd_num; + + struct sk_buff **tx_skb; + struct sk_buff **rx_skb; + + struct qtnf_tx_bd *tx_bd_vbase; + dma_addr_t tx_bd_pbase; + + struct qtnf_rx_bd *rx_bd_vbase; + dma_addr_t rx_bd_pbase; + + dma_addr_t bd_table_paddr; + void *bd_table_vaddr; + u32 bd_table_len; + + u32 hw_txproc_wr_ptr; + + u16 tx_bd_reclaim_start; + u16 tx_bd_index; + u32 tx_queue_len; + + u16 rx_bd_index; + + u32 pcie_irq_mask; + + /* diagnostics stats */ + u32 pcie_irq_count; + u32 pcie_irq_rx_count; + u32 pcie_irq_tx_count; + u32 tx_full_count; + u32 tx_done_count; + u32 tx_reclaim_done; + u32 tx_reclaim_req; +}; + +#endif /* _QTN_FMAC_PCIE_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h new file mode 100644 index 000000000000..e00d508fbcf0 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_PCIE_IPC_H_ +#define _QTN_FMAC_PCIE_IPC_H_ + +#include <linux/types.h> + +#include "shm_ipc_defs.h" + +/* bitmap for EP status and flags: updated by EP, read by RC */ +#define QTN_EP_HAS_UBOOT BIT(0) +#define QTN_EP_HAS_FIRMWARE BIT(1) +#define QTN_EP_REQ_UBOOT BIT(2) +#define QTN_EP_REQ_FIRMWARE BIT(3) +#define QTN_EP_ERROR_UBOOT BIT(4) +#define QTN_EP_ERROR_FIRMWARE BIT(5) + +#define QTN_EP_FW_LOADRDY BIT(8) +#define QTN_EP_FW_SYNC BIT(9) +#define QTN_EP_FW_RETRY BIT(10) +#define QTN_EP_FW_QLINK_DONE BIT(15) +#define QTN_EP_FW_DONE BIT(16) + +/* bitmap for RC status and flags: updated by RC, read by EP */ +#define QTN_RC_PCIE_LINK BIT(0) +#define QTN_RC_NET_LINK BIT(1) +#define QTN_RC_FW_FLASHBOOT BIT(5) +#define QTN_RC_FW_QLINK BIT(7) +#define QTN_RC_FW_LOADRDY BIT(8) +#define QTN_RC_FW_SYNC BIT(9) + +/* state transition timeouts */ +#define QTN_FW_DL_TIMEOUT_MS 3000 +#define QTN_FW_QLINK_TIMEOUT_MS 30000 + +#define PCIE_HDP_INT_RX_BITS (0 \ + | PCIE_HDP_INT_EP_TXDMA \ + | PCIE_HDP_INT_EP_TXEMPTY \ + ) + +#define PCIE_HDP_INT_TX_BITS (0 \ + | PCIE_HDP_INT_EP_RXDMA \ + ) + +#if BITS_PER_LONG == 64 +#define QTN_HOST_HI32(a) ((u32)(((u64)a) >> 32)) +#define QTN_HOST_LO32(a) ((u32)(((u64)a) & 0xffffffffUL)) +#define QTN_HOST_ADDR(h, l) ((((u64)h) << 32) | ((u64)l)) +#elif BITS_PER_LONG == 32 +#define QTN_HOST_HI32(a) 0 +#define QTN_HOST_LO32(a) ((u32)(((u32)a) & 0xffffffffUL)) +#define QTN_HOST_ADDR(h, l) ((u32)l) +#else +#error Unexpected BITS_PER_LONG value +#endif + +#define QTN_SYSCTL_BAR 0 +#define QTN_SHMEM_BAR 2 +#define QTN_DMA_BAR 3 + +#define QTN_PCIE_BDA_VERSION 0x1002 + +#define PCIE_BDA_NAMELEN 32 +#define PCIE_HHBM_MAX_SIZE 512 + +#define SKB_BUF_SIZE 2048 + +#define QTN_PCIE_BOARDFLG "PCIEQTN" +#define QTN_PCIE_FW_DLMASK 0xF +#define QTN_PCIE_FW_BUFSZ 2048 + +#define QTN_ENET_ADDR_LENGTH 6 + +#define QTN_TXDONE_MASK ((u32)0x80000000) +#define QTN_GET_LEN(x) ((x) & 0xFFFF) + +#define QTN_PCIE_TX_DESC_LEN_MASK 0xFFFF +#define QTN_PCIE_TX_DESC_LEN_SHIFT 0 +#define QTN_PCIE_TX_DESC_PORT_MASK 0xF +#define QTN_PCIE_TX_DESC_PORT_SHIFT 16 +#define QTN_PCIE_TX_DESC_TQE_BIT BIT(24) + +#define QTN_EP_LHOST_TQE_PORT 4 + +enum qtnf_pcie_bda_ipc_flags { + QTN_PCIE_IPC_FLAG_HBM_MAGIC = BIT(0), + QTN_PCIE_IPC_FLAG_SHM_PIO = BIT(1), +}; + +struct qtnf_pcie_bda { + __le16 bda_len; + __le16 bda_version; + __le32 bda_pci_endian; + __le32 bda_ep_state; + __le32 bda_rc_state; + __le32 bda_dma_mask; + __le32 bda_msi_addr; + __le32 bda_flashsz; + u8 bda_boardname[PCIE_BDA_NAMELEN]; + __le32 bda_rc_msi_enabled; + __le32 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; + __le32 bda_dsbw_start_index; + __le32 bda_dsbw_end_index; + __le32 bda_dsbw_total_bytes; + __le32 bda_rc_tx_bd_base; + __le32 bda_rc_tx_bd_num; + u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH]; + struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */ + struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */ +} __packed; + +struct qtnf_tx_bd { + __le32 addr; + __le32 addr_h; + __le32 info; + __le32 info_h; +} __packed; + +struct qtnf_rx_bd { + __le32 addr; + __le32 addr_h; + __le32 info; + __le32 info_h; + __le32 next_ptr; + __le32 next_ptr_h; +} __packed; + +enum qtnf_fw_loadtype { + QTN_FW_DBEGIN, + QTN_FW_DSUB, + QTN_FW_DEND, + QTN_FW_CTRL +}; + +struct qtnf_pcie_fw_hdr { + u8 boardflg[8]; + __le32 fwsize; + __le32 seqnum; + __le32 type; + __le32 pktlen; + __le32 crc; +} __packed; + +#endif /* _QTN_FMAC_PCIE_IPC_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h new file mode 100644 index 000000000000..78715b8a8ef9 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef __PEARL_PCIE_H +#define __PEARL_PCIE_H + +#define PCIE_GEN2_BASE (0xe9000000) +#define PCIE_GEN3_BASE (0xe7000000) + +#define PEARL_CUR_PCIE_BASE (PCIE_GEN2_BASE) +#define PCIE_HDP_OFFSET (0x2000) + +#define PCIE_HDP_CTRL(base) ((base) + 0x2c00) +#define PCIE_HDP_AXI_CTRL(base) ((base) + 0x2c04) +#define PCIE_HDP_HOST_WR_DESC0(base) ((base) + 0x2c10) +#define PCIE_HDP_HOST_WR_DESC0_H(base) ((base) + 0x2c14) +#define PCIE_HDP_HOST_WR_DESC1(base) ((base) + 0x2c18) +#define PCIE_HDP_HOST_WR_DESC1_H(base) ((base) + 0x2c1c) +#define PCIE_HDP_HOST_WR_DESC2(base) ((base) + 0x2c20) +#define PCIE_HDP_HOST_WR_DESC2_H(base) ((base) + 0x2c24) +#define PCIE_HDP_HOST_WR_DESC3(base) ((base) + 0x2c28) +#define PCIE_HDP_HOST_WR_DESC4_H(base) ((base) + 0x2c2c) +#define PCIE_HDP_RX_INT_CTRL(base) ((base) + 0x2c30) +#define PCIE_HDP_TX_INT_CTRL(base) ((base) + 0x2c34) +#define PCIE_HDP_INT_STATUS(base) ((base) + 0x2c38) +#define PCIE_HDP_INT_EN(base) ((base) + 0x2c3c) +#define PCIE_HDP_RX_DESC0_PTR(base) ((base) + 0x2c40) +#define PCIE_HDP_RX_DESC0_NOE(base) ((base) + 0x2c44) +#define PCIE_HDP_RX_DESC1_PTR(base) ((base) + 0x2c48) +#define PCIE_HDP_RX_DESC1_NOE(base) ((base) + 0x2c4c) +#define PCIE_HDP_RX_DESC2_PTR(base) ((base) + 0x2c50) +#define PCIE_HDP_RX_DESC2_NOE(base) ((base) + 0x2c54) +#define PCIE_HDP_RX_DESC3_PTR(base) ((base) + 0x2c58) +#define PCIE_HDP_RX_DESC3_NOE(base) ((base) + 0x2c5c) + +#define PCIE_HDP_TX0_BASE_ADDR(base) ((base) + 0x2c60) +#define PCIE_HDP_TX1_BASE_ADDR(base) ((base) + 0x2c64) +#define PCIE_HDP_TX0_Q_CTRL(base) ((base) + 0x2c70) +#define PCIE_HDP_TX1_Q_CTRL(base) ((base) + 0x2c74) +#define PCIE_HDP_CFG0(base) ((base) + 0x2c80) +#define PCIE_HDP_CFG1(base) ((base) + 0x2c84) +#define PCIE_HDP_CFG2(base) ((base) + 0x2c88) +#define PCIE_HDP_CFG3(base) ((base) + 0x2c8c) +#define PCIE_HDP_CFG4(base) ((base) + 0x2c90) +#define PCIE_HDP_CFG5(base) ((base) + 0x2c94) +#define PCIE_HDP_CFG6(base) ((base) + 0x2c98) +#define PCIE_HDP_CFG7(base) ((base) + 0x2c9c) +#define PCIE_HDP_CFG8(base) ((base) + 0x2ca0) +#define PCIE_HDP_CFG9(base) ((base) + 0x2ca4) +#define PCIE_HDP_CFG10(base) ((base) + 0x2ca8) +#define PCIE_HDP_CFG11(base) ((base) + 0x2cac) +#define PCIE_INT(base) ((base) + 0x2cb0) +#define PCIE_INT_MASK(base) ((base) + 0x2cb4) +#define PCIE_MSI_MASK(base) ((base) + 0x2cb8) +#define PCIE_MSI_PNDG(base) ((base) + 0x2cbc) +#define PCIE_PRI_CFG(base) ((base) + 0x2cc0) +#define PCIE_PHY_CR(base) ((base) + 0x2cc4) +#define PCIE_HDP_CTAG_CTRL(base) ((base) + 0x2cf4) +#define PCIE_HDP_HHBM_BUF_PTR(base) ((base) + 0x2d00) +#define PCIE_HDP_HHBM_BUF_PTR_H(base) ((base) + 0x2d04) +#define PCIE_HDP_HHBM_BUF_FIFO_NOE(base) ((base) + 0x2d04) +#define PCIE_HDP_RX0DMA_CNT(base) ((base) + 0x2d10) +#define PCIE_HDP_RX1DMA_CNT(base) ((base) + 0x2d14) +#define PCIE_HDP_RX2DMA_CNT(base) ((base) + 0x2d18) +#define PCIE_HDP_RX3DMA_CNT(base) ((base) + 0x2d1c) +#define PCIE_HDP_TX0DMA_CNT(base) ((base) + 0x2d20) +#define PCIE_HDP_TX1DMA_CNT(base) ((base) + 0x2d24) +#define PCIE_HDP_RXDMA_CTRL(base) ((base) + 0x2d28) +#define PCIE_HDP_TX_HOST_Q_SZ_CTRL(base) ((base) + 0x2d2c) +#define PCIE_HDP_TX_HOST_Q_BASE_L(base) ((base) + 0x2d30) +#define PCIE_HDP_TX_HOST_Q_BASE_H(base) ((base) + 0x2d34) +#define PCIE_HDP_TX_HOST_Q_WR_PTR(base) ((base) + 0x2d38) +#define PCIE_HDP_TX_HOST_Q_RD_PTR(base) ((base) + 0x2d3c) +#define PCIE_HDP_TX_HOST_Q_STS(base) ((base) + 0x2d40) + +/* Host HBM pool registers */ +#define PCIE_HHBM_CSR_REG(base) ((base) + 0x2e00) +#define PCIE_HHBM_Q_BASE_REG(base) ((base) + 0x2e04) +#define PCIE_HHBM_Q_LIMIT_REG(base) ((base) + 0x2e08) +#define PCIE_HHBM_Q_WR_REG(base) ((base) + 0x2e0c) +#define PCIE_HHBM_Q_RD_REG(base) ((base) + 0x2e10) +#define PCIE_HHBM_POOL_DATA_0_H(base) ((base) + 0x2e90) +#define PCIE_HHBM_CONFIG(base) ((base) + 0x2f9c) +#define PCIE_HHBM_POOL_REQ_0(base) ((base) + 0x2f10) +#define PCIE_HHBM_POOL_DATA_0(base) ((base) + 0x2f40) +#define PCIE_HHBM_WATERMARK_MASKED_INT(base) ((base) + 0x2f68) +#define PCIE_HHBM_WATERMARK_INT(base) ((base) + 0x2f6c) +#define PCIE_HHBM_POOL_WATERMARK(base) ((base) + 0x2f70) +#define PCIE_HHBM_POOL_OVERFLOW_CNT(base) ((base) + 0x2f90) +#define PCIE_HHBM_POOL_UNDERFLOW_CNT(base) ((base) + 0x2f94) +#define HBM_INT_STATUS(base) ((base) + 0x2f9c) +#define PCIE_HHBM_POOL_CNFIG(base) ((base) + 0x2f9c) + +/* host HBM bit field definition */ +#define HHBM_CONFIG_SOFT_RESET (BIT(8)) +#define HHBM_WR_REQ (BIT(0)) +#define HHBM_RD_REQ (BIT(1)) +#define HHBM_DONE (BIT(31)) + +/* offsets for dual PCIE */ +#define PCIE_PORT_LINK_CTL(base) ((base) + 0x0710) +#define PCIE_GEN2_CTL(base) ((base) + 0x080C) +#define PCIE_GEN3_OFF(base) ((base) + 0x0890) +#define PCIE_ATU_CTRL1(base) ((base) + 0x0904) +#define PCIE_ATU_CTRL2(base) ((base) + 0x0908) +#define PCIE_ATU_BASE_LOW(base) ((base) + 0x090C) +#define PCIE_ATU_BASE_HIGH(base) ((base) + 0x0910) +#define PCIE_ATU_BASE_LIMIT(base) ((base) + 0x0914) +#define PCIE_ATU_TGT_LOW(base) ((base) + 0x0918) +#define PCIE_ATU_TGT_HIGH(base) ((base) + 0x091C) +#define PCIE_DMA_WR_ENABLE(base) ((base) + 0x097C) +#define PCIE_DMA_WR_CHWTLOW(base) ((base) + 0x0988) +#define PCIE_DMA_WR_CHWTHIG(base) ((base) + 0x098C) +#define PCIE_DMA_WR_INTSTS(base) ((base) + 0x09BC) +#define PCIE_DMA_WR_INTMASK(base) ((base) + 0x09C4) +#define PCIE_DMA_WR_INTCLER(base) ((base) + 0x09C8) +#define PCIE_DMA_WR_DONE_IMWR_ADDR_L(base) ((base) + 0x09D0) +#define PCIE_DMA_WR_DONE_IMWR_ADDR_H(base) ((base) + 0x09D4) +#define PCIE_DMA_WR_ABORT_IMWR_ADDR_L(base) ((base) + 0x09D8) +#define PCIE_DMA_WR_ABORT_IMWR_ADDR_H(base) ((base) + 0x09DC) +#define PCIE_DMA_WR_IMWR_DATA(base) ((base) + 0x09E0) +#define PCIE_DMA_WR_LL_ERR_EN(base) ((base) + 0x0A00) +#define PCIE_DMA_WR_DOORBELL(base) ((base) + 0x0980) +#define PCIE_DMA_RD_ENABLE(base) ((base) + 0x099C) +#define PCIE_DMA_RD_DOORBELL(base) ((base) + 0x09A0) +#define PCIE_DMA_RD_CHWTLOW(base) ((base) + 0x09A8) +#define PCIE_DMA_RD_CHWTHIG(base) ((base) + 0x09AC) +#define PCIE_DMA_RD_INTSTS(base) ((base) + 0x0A10) +#define PCIE_DMA_RD_INTMASK(base) ((base) + 0x0A18) +#define PCIE_DMA_RD_INTCLER(base) ((base) + 0x0A1C) +#define PCIE_DMA_RD_ERR_STS_L(base) ((base) + 0x0A24) +#define PCIE_DMA_RD_ERR_STS_H(base) ((base) + 0x0A28) +#define PCIE_DMA_RD_LL_ERR_EN(base) ((base) + 0x0A34) +#define PCIE_DMA_RD_DONE_IMWR_ADDR_L(base) ((base) + 0x0A3C) +#define PCIE_DMA_RD_DONE_IMWR_ADDR_H(base) ((base) + 0x0A40) +#define PCIE_DMA_RD_ABORT_IMWR_ADDR_L(base) ((base) + 0x0A44) +#define PCIE_DMA_RD_ABORT_IMWR_ADDR_H(base) ((base) + 0x0A48) +#define PCIE_DMA_RD_IMWR_DATA(base) ((base) + 0x0A4C) +#define PCIE_DMA_CHNL_CONTEXT(base) ((base) + 0x0A6C) +#define PCIE_DMA_CHNL_CNTRL(base) ((base) + 0x0A70) +#define PCIE_DMA_XFR_SIZE(base) ((base) + 0x0A78) +#define PCIE_DMA_SAR_LOW(base) ((base) + 0x0A7C) +#define PCIE_DMA_SAR_HIGH(base) ((base) + 0x0A80) +#define PCIE_DMA_DAR_LOW(base) ((base) + 0x0A84) +#define PCIE_DMA_DAR_HIGH(base) ((base) + 0x0A88) +#define PCIE_DMA_LLPTR_LOW(base) ((base) + 0x0A8C) +#define PCIE_DMA_LLPTR_HIGH(base) ((base) + 0x0A90) +#define PCIE_DMA_WRLL_ERR_ENB(base) ((base) + 0x0A00) +#define PCIE_DMA_RDLL_ERR_ENB(base) ((base) + 0x0A34) +#define PCIE_DMABD_CHNL_CNTRL(base) ((base) + 0x8000) +#define PCIE_DMABD_XFR_SIZE(base) ((base) + 0x8004) +#define PCIE_DMABD_SAR_LOW(base) ((base) + 0x8008) +#define PCIE_DMABD_SAR_HIGH(base) ((base) + 0x800c) +#define PCIE_DMABD_DAR_LOW(base) ((base) + 0x8010) +#define PCIE_DMABD_DAR_HIGH(base) ((base) + 0x8014) +#define PCIE_DMABD_LLPTR_LOW(base) ((base) + 0x8018) +#define PCIE_DMABD_LLPTR_HIGH(base) ((base) + 0x801c) +#define PCIE_WRDMA0_CHNL_CNTRL(base) ((base) + 0x8000) +#define PCIE_WRDMA0_XFR_SIZE(base) ((base) + 0x8004) +#define PCIE_WRDMA0_SAR_LOW(base) ((base) + 0x8008) +#define PCIE_WRDMA0_SAR_HIGH(base) ((base) + 0x800c) +#define PCIE_WRDMA0_DAR_LOW(base) ((base) + 0x8010) +#define PCIE_WRDMA0_DAR_HIGH(base) ((base) + 0x8014) +#define PCIE_WRDMA0_LLPTR_LOW(base) ((base) + 0x8018) +#define PCIE_WRDMA0_LLPTR_HIGH(base) ((base) + 0x801c) +#define PCIE_WRDMA1_CHNL_CNTRL(base) ((base) + 0x8020) +#define PCIE_WRDMA1_XFR_SIZE(base) ((base) + 0x8024) +#define PCIE_WRDMA1_SAR_LOW(base) ((base) + 0x8028) +#define PCIE_WRDMA1_SAR_HIGH(base) ((base) + 0x802c) +#define PCIE_WRDMA1_DAR_LOW(base) ((base) + 0x8030) +#define PCIE_WRDMA1_DAR_HIGH(base) ((base) + 0x8034) +#define PCIE_WRDMA1_LLPTR_LOW(base) ((base) + 0x8038) +#define PCIE_WRDMA1_LLPTR_HIGH(base) ((base) + 0x803c) +#define PCIE_RDDMA0_CHNL_CNTRL(base) ((base) + 0x8040) +#define PCIE_RDDMA0_XFR_SIZE(base) ((base) + 0x8044) +#define PCIE_RDDMA0_SAR_LOW(base) ((base) + 0x8048) +#define PCIE_RDDMA0_SAR_HIGH(base) ((base) + 0x804c) +#define PCIE_RDDMA0_DAR_LOW(base) ((base) + 0x8050) +#define PCIE_RDDMA0_DAR_HIGH(base) ((base) + 0x8054) +#define PCIE_RDDMA0_LLPTR_LOW(base) ((base) + 0x8058) +#define PCIE_RDDMA0_LLPTR_HIGH(base) ((base) + 0x805c) +#define PCIE_RDDMA1_CHNL_CNTRL(base) ((base) + 0x8060) +#define PCIE_RDDMA1_XFR_SIZE(base) ((base) + 0x8064) +#define PCIE_RDDMA1_SAR_LOW(base) ((base) + 0x8068) +#define PCIE_RDDMA1_SAR_HIGH(base) ((base) + 0x806c) +#define PCIE_RDDMA1_DAR_LOW(base) ((base) + 0x8070) +#define PCIE_RDDMA1_DAR_HIGH(base) ((base) + 0x8074) +#define PCIE_RDDMA1_LLPTR_LOW(base) ((base) + 0x8078) +#define PCIE_RDDMA1_LLPTR_HIGH(base) ((base) + 0x807c) + +#define PCIE_ID(base) ((base) + 0x0000) +#define PCIE_CMD(base) ((base) + 0x0004) +#define PCIE_BAR(base, n) ((base) + 0x0010 + ((n) << 2)) +#define PCIE_CAP_PTR(base) ((base) + 0x0034) +#define PCIE_MSI_LBAR(base) ((base) + 0x0054) +#define PCIE_MSI_CTRL(base) ((base) + 0x0050) +#define PCIE_MSI_ADDR_L(base) ((base) + 0x0054) +#define PCIE_MSI_ADDR_H(base) ((base) + 0x0058) +#define PCIE_MSI_DATA(base) ((base) + 0x005C) +#define PCIE_MSI_MASK_BIT(base) ((base) + 0x0060) +#define PCIE_MSI_PEND_BIT(base) ((base) + 0x0064) +#define PCIE_DEVCAP(base) ((base) + 0x0074) +#define PCIE_DEVCTLSTS(base) ((base) + 0x0078) + +#define PCIE_CMDSTS(base) ((base) + 0x0004) +#define PCIE_LINK_STAT(base) ((base) + 0x80) +#define PCIE_LINK_CTL2(base) ((base) + 0xa0) +#define PCIE_ASPM_L1_CTRL(base) ((base) + 0x70c) +#define PCIE_ASPM_LINK_CTRL(base) (PCIE_LINK_STAT) +#define PCIE_ASPM_L1_SUBSTATE_TIMING(base) ((base) + 0xB44) +#define PCIE_L1SUB_CTRL1(base) ((base) + 0x150) +#define PCIE_PMCSR(base) ((base) + 0x44) +#define PCIE_CFG_SPACE_LIMIT(base) ((base) + 0x100) + +/* PCIe link defines */ +#define PEARL_PCIE_LINKUP (0x7) +#define PEARL_PCIE_DATA_LINK (BIT(0)) +#define PEARL_PCIE_PHY_LINK (BIT(1)) +#define PEARL_PCIE_LINK_RST (BIT(3)) +#define PEARL_PCIE_FATAL_ERR (BIT(5)) +#define PEARL_PCIE_NONFATAL_ERR (BIT(6)) + +/* PCIe Lane defines */ +#define PCIE_G2_LANE_X1 ((BIT(0)) << 16) +#define PCIE_G2_LANE_X2 ((BIT(0) | BIT(1)) << 16) + +/* PCIe DLL link enable */ +#define PCIE_DLL_LINK_EN ((BIT(0)) << 5) + +#define PCIE_LINK_GEN1 (BIT(0)) +#define PCIE_LINK_GEN2 (BIT(1)) +#define PCIE_LINK_GEN3 (BIT(2)) +#define PCIE_LINK_MODE(x) (((x) >> 16) & 0x7) + +#define MSI_EN (BIT(0)) +#define MSI_64_EN (BIT(7)) +#define PCIE_MSI_ADDR_OFFSET(a) ((a) & 0xFFFF) +#define PCIE_MSI_ADDR_ALIGN(a) ((a) & (~0xFFFF)) + +#define PCIE_BAR_MASK(base, n) ((base) + 0x1010 + ((n) << 2)) +#define PCIE_MAX_BAR (6) + +#define PCIE_ATU_VIEW(base) ((base) + 0x0900) +#define PCIE_ATU_CTL1(base) ((base) + 0x0904) +#define PCIE_ATU_CTL2(base) ((base) + 0x0908) +#define PCIE_ATU_LBAR(base) ((base) + 0x090c) +#define PCIE_ATU_UBAR(base) ((base) + 0x0910) +#define PCIE_ATU_LAR(base) ((base) + 0x0914) +#define PCIE_ATU_LTAR(base) ((base) + 0x0918) +#define PCIE_ATU_UTAR(base) ((base) + 0x091c) + +#define PCIE_MSI_ADDR_LOWER(base) ((base) + 0x0820) +#define PCIE_MSI_ADDR_UPPER(base) ((base) + 0x0824) +#define PCIE_MSI_ENABLE(base) ((base) + 0x0828) +#define PCIE_MSI_MASK_RC(base) ((base) + 0x082c) +#define PCIE_MSI_STATUS(base) ((base) + 0x0830) +#define PEARL_PCIE_MSI_REGION (0xce000000) +#define PEARL_PCIE_MSI_DATA (0) +#define PCIE_MSI_GPIO(base) ((base) + 0x0888) + +#define PCIE_HDP_HOST_QUEUE_FULL (BIT(17)) +#define USE_BAR_MATCH_MODE +#define PCIE_ATU_OB_REGION (BIT(0)) +#define PCIE_ATU_EN_REGION (BIT(31)) +#define PCIE_ATU_EN_MATCH (BIT(30)) +#define PCIE_BASE_REGION (0xb0000000) +#define PCIE_MEM_MAP_SIZE (512 * 1024) + +#define PCIE_OB_REG_REGION (0xcf000000) +#define PCIE_CONFIG_REGION (0xcf000000) +#define PCIE_CONFIG_SIZE (4096) +#define PCIE_CONFIG_CH (1) + +/* inbound mapping */ +#define PCIE_IB_BAR0 (0x00000000) /* ddr */ +#define PCIE_IB_BAR0_CH (0) +#define PCIE_IB_BAR3 (0xe0000000) /* sys_reg */ +#define PCIE_IB_BAR3_CH (1) + +/* outbound mapping */ +#define PCIE_MEM_CH (0) +#define PCIE_REG_CH (1) +#define PCIE_MEM_REGION (0xc0000000) +#define PCIE_MEM_SIZE (0x000fffff) +#define PCIE_MEM_TAR (0x80000000) + +#define PCIE_MSI_REGION (0xce000000) +#define PCIE_MSI_SIZE (KBYTE(4) - 1) +#define PCIE_MSI_CH (1) + +/* size of config region */ +#define PCIE_CFG_SIZE (0x0000ffff) + +#define PCIE_ATU_DIR_IB (BIT(31)) +#define PCIE_ATU_DIR_OB (0) +#define PCIE_ATU_DIR_CFG (2) +#define PCIE_ATU_DIR_MATCH_IB (BIT(31) | BIT(30)) + +#define PCIE_DMA_WR_0 (0) +#define PCIE_DMA_WR_1 (1) +#define PCIE_DMA_RD_0 (2) +#define PCIE_DMA_RD_1 (3) + +#define PCIE_DMA_CHNL_CNTRL_CB (BIT(0)) +#define PCIE_DMA_CHNL_CNTRL_TCB (BIT(1)) +#define PCIE_DMA_CHNL_CNTRL_LLP (BIT(2)) +#define PCIE_DMA_CHNL_CNTRL_LIE (BIT(3)) +#define PCIE_DMA_CHNL_CNTRL_RIE (BIT(4)) +#define PCIE_DMA_CHNL_CNTRL_CSS (BIT(8)) +#define PCIE_DMA_CHNL_CNTRL_LLE (BIT(9)) +#define PCIE_DMA_CHNL_CNTRL_TLP (BIT(26)) + +#define PCIE_DMA_CHNL_CONTEXT_RD (BIT(31)) +#define PCIE_DMA_CHNL_CONTEXT_WR (0) +#define PCIE_MAX_BAR (6) + +/* PCIe HDP interrupt status definition */ +#define PCIE_HDP_INT_EP_RXDMA (BIT(0)) +#define PCIE_HDP_INT_HBM_UF (BIT(1)) +#define PCIE_HDP_INT_RX_LEN_ERR (BIT(2)) +#define PCIE_HDP_INT_RX_HDR_LEN_ERR (BIT(3)) +#define PCIE_HDP_INT_EP_TXDMA (BIT(12)) +#define PCIE_HDP_INT_EP_TXEMPTY (BIT(15)) +#define PCIE_HDP_INT_IPC (BIT(29)) + +/* PCIe interrupt status definition */ +#define PCIE_INT_MSI (BIT(24)) +#define PCIE_INT_INTX (BIT(23)) + +/* PCIe legacy INTx */ +#define PEARL_PCIE_CFG0_OFFSET (0x6C) +#define PEARL_ASSERT_INTX (BIT(9)) + +/* SYS CTL regs */ +#define QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET (0x001C) + +#define QTN_PEARL_IPC_IRQ_WORD(irq) (BIT(irq) | BIT(irq + 16)) +#define QTN_PEARL_LHOST_IPC_IRQ (6) + +#endif /* __PEARL_PCIE_H */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h new file mode 100644 index 000000000000..6eafc15e0065 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -0,0 +1,901 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_QLINK_H_ +#define _QTN_QLINK_H_ + +#include <linux/ieee80211.h> + +#define QLINK_PROTO_VER 3 + +#define QLINK_MACID_RSVD 0xFF +#define QLINK_VIFID_RSVD 0xFF + +/* Common QLINK protocol messages definitions. + */ + +/** + * enum qlink_msg_type - QLINK message types + * + * Used to distinguish between message types of QLINK protocol. + * + * @QLINK_MSG_TYPE_CMD: Message is carrying data of a command sent from + * driver to wireless hardware. + * @QLINK_MSG_TYPE_CMDRSP: Message is carrying data of a response to a command. + * Sent from wireless HW to driver in reply to previously issued command. + * @QLINK_MSG_TYPE_EVENT: Data for an event originated in wireless hardware and + * sent asynchronously to driver. + */ +enum qlink_msg_type { + QLINK_MSG_TYPE_CMD = 1, + QLINK_MSG_TYPE_CMDRSP = 2, + QLINK_MSG_TYPE_EVENT = 3 +}; + +/** + * struct qlink_msg_header - common QLINK protocol message header + * + * Portion of QLINK protocol header common for all message types. + * + * @type: Message type, one of &enum qlink_msg_type. + * @len: Total length of message including all headers. + */ +struct qlink_msg_header { + __le16 type; + __le16 len; +} __packed; + +/* Generic definitions of data and information carried in QLINK messages + */ + +enum qlink_hw_capab { + QLINK_HW_SUPPORTS_REG_UPDATE = BIT(0), +}; + +enum qlink_phy_mode { + QLINK_PHYMODE_BGN = BIT(0), + QLINK_PHYMODE_AN = BIT(1), + QLINK_PHYMODE_AC = BIT(2), +}; + +enum qlink_iface_type { + QLINK_IFTYPE_AP = 1, + QLINK_IFTYPE_STATION = 2, + QLINK_IFTYPE_ADHOC = 3, + QLINK_IFTYPE_MONITOR = 4, + QLINK_IFTYPE_WDS = 5, +}; + +/** + * struct qlink_intf_info - information on virtual interface. + * + * Data describing a single virtual interface. + * + * @if_type: Mode of interface operation, one of &enum qlink_iface_type + * @flags: interface flagsmap. + * @mac_addr: MAC address of virtual interface. + */ +struct qlink_intf_info { + __le16 if_type; + __le16 flags; + u8 mac_addr[ETH_ALEN]; + u8 rsvd[2]; +} __packed; + +enum qlink_sta_flags { + QLINK_STA_FLAG_INVALID = 0, + QLINK_STA_FLAG_AUTHORIZED = BIT(0), + QLINK_STA_FLAG_SHORT_PREAMBLE = BIT(1), + QLINK_STA_FLAG_WME = BIT(2), + QLINK_STA_FLAG_MFP = BIT(3), + QLINK_STA_FLAG_AUTHENTICATED = BIT(4), + QLINK_STA_FLAG_TDLS_PEER = BIT(5), + QLINK_STA_FLAG_ASSOCIATED = BIT(6), +}; + +enum qlink_channel_width { + QLINK_CHAN_WIDTH_5 = BIT(0), + QLINK_CHAN_WIDTH_10 = BIT(1), + QLINK_CHAN_WIDTH_20_NOHT = BIT(2), + QLINK_CHAN_WIDTH_20 = BIT(3), + QLINK_CHAN_WIDTH_40 = BIT(4), + QLINK_CHAN_WIDTH_80 = BIT(5), + QLINK_CHAN_WIDTH_80P80 = BIT(6), + QLINK_CHAN_WIDTH_160 = BIT(7), +}; + +/* QLINK Command messages related definitions + */ + +/** + * enum qlink_cmd_type - list of supported commands + * + * Commands are QLINK messages of type @QLINK_MSG_TYPE_CMD, sent by driver to + * wireless network device for processing. Device is expected to send back a + * reply message of type &QLINK_MSG_TYPE_CMDRSP, containing at least command + * execution status (one of &enum qlink_cmd_result) at least. Reply message + * may also contain data payload specific to the command type. + * + * @QLINK_CMD_CHANS_INFO_GET: for the specified MAC and specified band, get + * number of operational channels and information on each of the channel. + * This command is generic to a specified MAC, interface index must be set + * to QLINK_VIFID_RSVD in command header. + */ +enum qlink_cmd_type { + QLINK_CMD_FW_INIT = 0x0001, + QLINK_CMD_FW_DEINIT = 0x0002, + QLINK_CMD_REGISTER_MGMT = 0x0003, + QLINK_CMD_SEND_MGMT_FRAME = 0x0004, + QLINK_CMD_MGMT_SET_APPIE = 0x0005, + QLINK_CMD_PHY_PARAMS_GET = 0x0011, + QLINK_CMD_PHY_PARAMS_SET = 0x0012, + QLINK_CMD_GET_HW_INFO = 0x0013, + QLINK_CMD_MAC_INFO = 0x0014, + QLINK_CMD_ADD_INTF = 0x0015, + QLINK_CMD_DEL_INTF = 0x0016, + QLINK_CMD_CHANGE_INTF = 0x0017, + QLINK_CMD_UPDOWN_INTF = 0x0018, + QLINK_CMD_REG_REGION = 0x0019, + QLINK_CMD_CHANS_INFO_GET = 0x001A, + QLINK_CMD_CONFIG_AP = 0x0020, + QLINK_CMD_START_AP = 0x0021, + QLINK_CMD_STOP_AP = 0x0022, + QLINK_CMD_GET_STA_INFO = 0x0030, + QLINK_CMD_ADD_KEY = 0x0040, + QLINK_CMD_DEL_KEY = 0x0041, + QLINK_CMD_SET_DEFAULT_KEY = 0x0042, + QLINK_CMD_SET_DEFAULT_MGMT_KEY = 0x0043, + QLINK_CMD_CHANGE_STA = 0x0051, + QLINK_CMD_DEL_STA = 0x0052, + QLINK_CMD_SCAN = 0x0053, + QLINK_CMD_CONNECT = 0x0060, + QLINK_CMD_DISCONNECT = 0x0061, +}; + +/** + * struct qlink_cmd - QLINK command message header + * + * Header used for QLINK messages of QLINK_MSG_TYPE_CMD type. + * + * @mhdr: Common QLINK message header. + * @cmd_id: command id, one of &enum qlink_cmd_type. + * @seq_num: sequence number of command message, used for matching with + * response message. + * @macid: index of physical radio device the command is destined to or + * QLINK_MACID_RSVD if not applicable. + * @vifid: index of virtual wireless interface on specified @macid the command + * is destined to or QLINK_VIFID_RSVD if not applicable. + */ +struct qlink_cmd { + struct qlink_msg_header mhdr; + __le16 cmd_id; + __le16 seq_num; + u8 rsvd[2]; + u8 macid; + u8 vifid; +} __packed; + +/** + * struct qlink_cmd_manage_intf - interface management command + * + * Data for interface management commands QLINK_CMD_ADD_INTF, QLINK_CMD_DEL_INTF + * and QLINK_CMD_CHANGE_INTF. + * + * @intf_info: interface description. + */ +struct qlink_cmd_manage_intf { + struct qlink_cmd chdr; + struct qlink_intf_info intf_info; +} __packed; + +enum qlink_mgmt_frame_type { + QLINK_MGMT_FRAME_ASSOC_REQ = 0x00, + QLINK_MGMT_FRAME_ASSOC_RESP = 0x01, + QLINK_MGMT_FRAME_REASSOC_REQ = 0x02, + QLINK_MGMT_FRAME_REASSOC_RESP = 0x03, + QLINK_MGMT_FRAME_PROBE_REQ = 0x04, + QLINK_MGMT_FRAME_PROBE_RESP = 0x05, + QLINK_MGMT_FRAME_BEACON = 0x06, + QLINK_MGMT_FRAME_ATIM = 0x07, + QLINK_MGMT_FRAME_DISASSOC = 0x08, + QLINK_MGMT_FRAME_AUTH = 0x09, + QLINK_MGMT_FRAME_DEAUTH = 0x0A, + QLINK_MGMT_FRAME_ACTION = 0x0B, + + QLINK_MGMT_FRAME_TYPE_COUNT +}; + +/** + * struct qlink_cmd_mgmt_frame_register - data for QLINK_CMD_REGISTER_MGMT + * + * @frame_type: MGMT frame type the registration request describes, one of + * &enum qlink_mgmt_frame_type. + * @do_register: 0 - unregister, otherwise register for reception of specified + * MGMT frame type. + */ +struct qlink_cmd_mgmt_frame_register { + struct qlink_cmd chdr; + __le16 frame_type; + u8 do_register; +} __packed; + +enum qlink_mgmt_frame_tx_flags { + QLINK_MGMT_FRAME_TX_FLAG_NONE = 0, + QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN = BIT(0), + QLINK_MGMT_FRAME_TX_FLAG_NO_CCK = BIT(1), + QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT = BIT(2), +}; + +/** + * struct qlink_cmd_mgmt_frame_tx - data for QLINK_CMD_SEND_MGMT_FRAME command + * + * @cookie: opaque request identifier. + * @freq: Frequency to use for frame transmission. + * @flags: Transmission flags, one of &enum qlink_mgmt_frame_tx_flags. + * @frame_data: frame to transmit. + */ +struct qlink_cmd_mgmt_frame_tx { + struct qlink_cmd chdr; + __le32 cookie; + __le16 freq; + __le16 flags; + u8 frame_data[0]; +} __packed; + +/** + * struct qlink_cmd_mgmt_append_ie - data for QLINK_CMD_MGMT_SET_APPIE command + * + * @type: type of MGMT frame to appent requested IEs to, one of + * &enum qlink_mgmt_frame_type. + * @flags: for future use. + * @ie_data: IEs data to append. + */ +struct qlink_cmd_mgmt_append_ie { + struct qlink_cmd chdr; + u8 type; + u8 flags; + u8 ie_data[0]; +} __packed; + +/** + * struct qlink_cmd_get_sta_info - data for QLINK_CMD_GET_STA_INFO command + * + * @sta_addr: MAC address of the STA statistics is requested for. + */ +struct qlink_cmd_get_sta_info { + struct qlink_cmd chdr; + u8 sta_addr[ETH_ALEN]; +} __packed; + +/** + * struct qlink_cmd_add_key - data for QLINK_CMD_ADD_KEY command. + * + * @key_index: index of the key being installed. + * @pairwise: whether to use pairwise key. + * @addr: MAC address of a STA key is being installed to. + * @cipher: cipher suite. + * @key_data: key data itself. + */ +struct qlink_cmd_add_key { + struct qlink_cmd chdr; + u8 key_index; + u8 pairwise; + u8 addr[ETH_ALEN]; + __le32 cipher; + u8 key_data[0]; +} __packed; + +/** + * struct qlink_cmd_del_key_req - data for QLINK_CMD_DEL_KEY command + * + * @key_index: index of the key being removed. + * @pairwise: whether to use pairwise key. + * @addr: MAC address of a STA for which a key is removed. + */ +struct qlink_cmd_del_key { + struct qlink_cmd chdr; + u8 key_index; + u8 pairwise; + u8 addr[ETH_ALEN]; +} __packed; + +/** + * struct qlink_cmd_set_def_key - data for QLINK_CMD_SET_DEFAULT_KEY command + * + * @key_index: index of the key to be set as default one. + * @unicast: key is unicast. + * @multicast: key is multicast. + */ +struct qlink_cmd_set_def_key { + struct qlink_cmd chdr; + u8 key_index; + u8 unicast; + u8 multicast; +} __packed; + +/** + * struct qlink_cmd_set_def_mgmt_key - data for QLINK_CMD_SET_DEFAULT_MGMT_KEY + * + * @key_index: index of the key to be set as default MGMT key. + */ +struct qlink_cmd_set_def_mgmt_key { + struct qlink_cmd chdr; + u8 key_index; +} __packed; + +/** + * struct qlink_cmd_change_sta - data for QLINK_CMD_CHANGE_STA command + * + * @sta_flags_mask: STA flags mask, bitmap of &enum qlink_sta_flags + * @sta_flags_set: STA flags values, bitmap of &enum qlink_sta_flags + * @sta_addr: address of the STA for which parameters are set. + */ +struct qlink_cmd_change_sta { + struct qlink_cmd chdr; + __le32 sta_flags_mask; + __le32 sta_flags_set; + u8 sta_addr[ETH_ALEN]; +} __packed; + +/** + * struct qlink_cmd_del_sta - data for QLINK_CMD_DEL_STA command. + * + * See &struct station_del_parameters + */ +struct qlink_cmd_del_sta { + struct qlink_cmd chdr; + __le16 reason_code; + u8 subtype; + u8 sta_addr[ETH_ALEN]; +} __packed; + +enum qlink_sta_connect_flags { + QLINK_STA_CONNECT_DISABLE_HT = BIT(0), + QLINK_STA_CONNECT_DISABLE_VHT = BIT(1), + QLINK_STA_CONNECT_USE_RRM = BIT(2), +}; + +/** + * struct qlink_cmd_connect - data for QLINK_CMD_CONNECT command + * + * @flags: for future use. + * @freq: center frequence of a channel which should be used to connect. + * @bg_scan_period: period of background scan. + * @bssid: BSSID of the BSS to connect to. + * @payload: variable portion of connection request. + */ +struct qlink_cmd_connect { + struct qlink_cmd chdr; + __le32 flags; + __le16 freq; + __le16 bg_scan_period; + u8 bssid[ETH_ALEN]; + u8 payload[0]; +} __packed; + +/** + * struct qlink_cmd_disconnect - data for QLINK_CMD_DISCONNECT command + * + * @reason: code of the reason of disconnect, see &enum ieee80211_reasoncode. + */ +struct qlink_cmd_disconnect { + struct qlink_cmd chdr; + __le16 reason; +} __packed; + +/** + * struct qlink_cmd_updown - data for QLINK_CMD_UPDOWN_INTF command + * + * @if_up: bring specified interface DOWN (if_up==0) or UP (otherwise). + * Interface is specified in common command header @chdr. + */ +struct qlink_cmd_updown { + struct qlink_cmd chdr; + u8 if_up; +} __packed; + +/** + * enum qlink_band - a list of frequency bands + * + * @QLINK_BAND_2GHZ: 2.4GHz band + * @QLINK_BAND_5GHZ: 5GHz band + * @QLINK_BAND_60GHZ: 60GHz band + */ +enum qlink_band { + QLINK_BAND_2GHZ = BIT(0), + QLINK_BAND_5GHZ = BIT(1), + QLINK_BAND_60GHZ = BIT(2), +}; + +/** + * struct qlink_cmd_chans_info_get - data for QLINK_CMD_CHANS_INFO_GET command + * + * @band: a PHY band for which channels info is needed, one of @enum qlink_band + */ +struct qlink_cmd_chans_info_get { + struct qlink_cmd chdr; + u8 band; +} __packed; + +/* QLINK Command Responses messages related definitions + */ + +enum qlink_cmd_result { + QLINK_CMD_RESULT_OK = 0, + QLINK_CMD_RESULT_INVALID, + QLINK_CMD_RESULT_ENOTSUPP, + QLINK_CMD_RESULT_ENOTFOUND, +}; + +/** + * struct qlink_resp - QLINK command response message header + * + * Header used for QLINK messages of QLINK_MSG_TYPE_CMDRSP type. + * + * @mhdr: see &struct qlink_msg_header. + * @cmd_id: command ID the response corresponds to, one of &enum qlink_cmd_type. + * @seq_num: sequence number of command message, used for matching with + * response message. + * @result: result of the command execution, one of &enum qlink_cmd_result. + * @macid: index of physical radio device the response is sent from or + * QLINK_MACID_RSVD if not applicable. + * @vifid: index of virtual wireless interface on specified @macid the response + * is sent from or QLINK_VIFID_RSVD if not applicable. + */ +struct qlink_resp { + struct qlink_msg_header mhdr; + __le16 cmd_id; + __le16 seq_num; + __le16 result; + u8 macid; + u8 vifid; +} __packed; + +/** + * struct qlink_resp_get_mac_info - response for QLINK_CMD_MAC_INFO command + * + * Data describing specific physical device providing wireless MAC + * functionality. + * + * @dev_mac: MAC address of physical WMAC device (used for first BSS on + * specified WMAC). + * @num_tx_chain: Number of transmit chains used by WMAC. + * @num_rx_chain: Number of receive chains used by WMAC. + * @vht_cap: VHT capabilities. + * @ht_cap: HT capabilities. + * @bands_cap: wireless bands WMAC can operate in, bitmap of &enum qlink_band. + * @phymode_cap: PHY modes WMAC can operate in, bitmap of &enum qlink_phy_mode. + * @max_ap_assoc_sta: Maximum number of associations supported by WMAC. + * @radar_detect_widths: bitmask of channels BW for which WMAC can detect radar. + * @var_info: variable-length WMAC info data. + */ +struct qlink_resp_get_mac_info { + struct qlink_resp rhdr; + u8 dev_mac[ETH_ALEN]; + u8 num_tx_chain; + u8 num_rx_chain; + struct ieee80211_vht_cap vht_cap; + struct ieee80211_ht_cap ht_cap; + u8 bands_cap; + u8 phymode_cap; + __le16 max_ap_assoc_sta; + __le16 radar_detect_widths; + u8 var_info[0]; +} __packed; + +/** + * struct qlink_resp_get_hw_info - response for QLINK_CMD_GET_HW_INFO command + * + * Description of wireless hardware capabilities and features. + * + * @fw_ver: wireless hardware firmware version. + * @hw_capab: Bitmap of capabilities supported by firmware. + * @ql_proto_ver: Version of QLINK protocol used by firmware. + * @country_code: country code ID firmware is configured to. + * @num_mac: Number of separate physical radio devices provided by hardware. + * @mac_bitmap: Bitmap of MAC IDs that are active and can be used in firmware. + * @total_tx_chains: total number of transmit chains used by device. + * @total_rx_chains: total number of receive chains. + */ +struct qlink_resp_get_hw_info { + struct qlink_resp rhdr; + __le32 fw_ver; + __le32 hw_capab; + __le16 ql_proto_ver; + u8 alpha2_code[2]; + u8 num_mac; + u8 mac_bitmap; + u8 total_tx_chain; + u8 total_rx_chain; +} __packed; + +/** + * struct qlink_resp_manage_intf - response for interface management commands + * + * Response data for QLINK_CMD_ADD_INTF and QLINK_CMD_CHANGE_INTF commands. + * + * @rhdr: Common Command Response message header. + * @intf_info: interface description. + */ +struct qlink_resp_manage_intf { + struct qlink_resp rhdr; + struct qlink_intf_info intf_info; +} __packed; + +/** + * struct qlink_resp_get_sta_info - response for QLINK_CMD_GET_STA_INFO command + * + * Response data containing statistics for specified STA. + * + * @sta_addr: MAC address of STA the response carries statistic for. + * @info: statistics for specified STA. + */ +struct qlink_resp_get_sta_info { + struct qlink_resp rhdr; + u8 sta_addr[ETH_ALEN]; + u8 info[0]; +} __packed; + +/** + * struct qlink_resp_get_chan_info - response for QLINK_CMD_CHANS_INFO_GET cmd + * + * @band: frequency band to which channels belong to, one of @enum qlink_band. + * @num_chans: total number of channels info data contained in reply data. + * @info: variable-length channels info. + */ +struct qlink_resp_get_chan_info { + struct qlink_resp rhdr; + u8 band; + u8 num_chans; + u8 rsvd[2]; + u8 info[0]; +} __packed; + +/** + * struct qlink_resp_phy_params - response for QLINK_CMD_PHY_PARAMS_GET command + * + * @info: variable-length array of PHY params. + */ +struct qlink_resp_phy_params { + struct qlink_resp rhdr; + u8 info[0]; +} __packed; + +/* QLINK Events messages related definitions + */ + +enum qlink_event_type { + QLINK_EVENT_STA_ASSOCIATED = 0x0021, + QLINK_EVENT_STA_DEAUTH = 0x0022, + QLINK_EVENT_MGMT_RECEIVED = 0x0023, + QLINK_EVENT_SCAN_RESULTS = 0x0024, + QLINK_EVENT_SCAN_COMPLETE = 0x0025, + QLINK_EVENT_BSS_JOIN = 0x0026, + QLINK_EVENT_BSS_LEAVE = 0x0027, +}; + +/** + * struct qlink_event - QLINK event message header + * + * Header used for QLINK messages of QLINK_MSG_TYPE_EVENT type. + * + * @mhdr: Common QLINK message header. + * @event_id: Specifies specific event ID, one of &enum qlink_event_type. + * @macid: index of physical radio device the event was generated on or + * QLINK_MACID_RSVD if not applicable. + * @vifid: index of virtual wireless interface on specified @macid the event + * was generated on or QLINK_VIFID_RSVD if not applicable. + */ +struct qlink_event { + struct qlink_msg_header mhdr; + __le16 event_id; + u8 macid; + u8 vifid; +} __packed; + +/** + * struct qlink_event_sta_assoc - data for QLINK_EVENT_STA_ASSOCIATED event + * + * @sta_addr: Address of a STA for which new association event was generated + * @frame_control: control bits from 802.11 ASSOC_REQUEST header. + * @payload: IEs from association request. + */ +struct qlink_event_sta_assoc { + struct qlink_event ehdr; + u8 sta_addr[ETH_ALEN]; + __le16 frame_control; + u8 ies[0]; +} __packed; + +/** + * struct qlink_event_sta_deauth - data for QLINK_EVENT_STA_DEAUTH event + * + * @sta_addr: Address of a deauthenticated STA. + * @reason: reason for deauthentication. + */ +struct qlink_event_sta_deauth { + struct qlink_event ehdr; + u8 sta_addr[ETH_ALEN]; + __le16 reason; +} __packed; + +/** + * struct qlink_event_bss_join - data for QLINK_EVENT_BSS_JOIN event + * + * @bssid: BSSID of a BSS which interface tried to joined. + * @status: status of joining attempt, see &enum ieee80211_statuscode. + */ +struct qlink_event_bss_join { + struct qlink_event ehdr; + u8 bssid[ETH_ALEN]; + __le16 status; +} __packed; + +/** + * struct qlink_event_bss_leave - data for QLINK_EVENT_BSS_LEAVE event + * + * @reason: reason of disconnecting from BSS. + */ +struct qlink_event_bss_leave { + struct qlink_event ehdr; + u16 reason; +} __packed; + +enum qlink_rxmgmt_flags { + QLINK_RXMGMT_FLAG_ANSWERED = 1 << 0, +}; + +/** + * struct qlink_event_rxmgmt - data for QLINK_EVENT_MGMT_RECEIVED event + * + * @freq: Frequency on which the frame was received in MHz. + * @sig_dbm: signal strength in dBm. + * @flags: bitmap of &enum qlink_rxmgmt_flags. + * @frame_data: data of Rx'd frame itself. + */ +struct qlink_event_rxmgmt { + struct qlink_event ehdr; + __le32 freq; + __le32 sig_dbm; + __le32 flags; + u8 frame_data[0]; +} __packed; + +enum qlink_frame_type { + QLINK_BSS_FTYPE_UNKNOWN, + QLINK_BSS_FTYPE_BEACON, + QLINK_BSS_FTYPE_PRESP, +}; + +/** + * struct qlink_event_scan_result - data for QLINK_EVENT_SCAN_RESULTS event + * + * @tsf: TSF timestamp indicating when scan results were generated. + * @freq: Center frequency of the channel where BSS for which the scan result + * event was generated was discovered. + * @capab: capabilities field. + * @bintval: beacon interval announced by discovered BSS. + * @signal: signal strength. + * @frame_type: frame type used to get scan result, see &enum qlink_frame_type. + * @bssid: BSSID announced by discovered BSS. + * @ssid_len: length of SSID announced by BSS. + * @ssid: SSID announced by discovered BSS. + * @payload: IEs that are announced by discovered BSS in its MGMt frames. + */ +struct qlink_event_scan_result { + struct qlink_event ehdr; + __le64 tsf; + __le16 freq; + __le16 capab; + __le16 bintval; + s8 signal; + u8 frame_type; + u8 bssid[ETH_ALEN]; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 payload[0]; +} __packed; + +/** + * enum qlink_scan_complete_flags - indicates result of scan request. + * + * @QLINK_SCAN_NONE: Scan request was processed. + * @QLINK_SCAN_ABORTED: Scan was aborted. + */ +enum qlink_scan_complete_flags { + QLINK_SCAN_NONE = 0, + QLINK_SCAN_ABORTED = BIT(0), +}; + +/** + * struct qlink_event_scan_complete - data for QLINK_EVENT_SCAN_COMPLETE event + * + * @flags: flags indicating the status of pending scan request, + * see &enum qlink_scan_complete_flags. + */ +struct qlink_event_scan_complete { + struct qlink_event ehdr; + __le32 flags; +} __packed; + +/* QLINK TLVs (Type-Length Values) definitions + */ + +enum qlink_tlv_id { + QTN_TLV_ID_FRAG_THRESH = 0x0201, + QTN_TLV_ID_RTS_THRESH = 0x0202, + QTN_TLV_ID_SRETRY_LIMIT = 0x0203, + QTN_TLV_ID_LRETRY_LIMIT = 0x0204, + QTN_TLV_ID_BCN_PERIOD = 0x0205, + QTN_TLV_ID_DTIM = 0x0206, + QTN_TLV_ID_CHANNEL = 0x020F, + QTN_TLV_ID_COVERAGE_CLASS = 0x0213, + QTN_TLV_ID_IFACE_LIMIT = 0x0214, + QTN_TLV_ID_NUM_IFACE_COMB = 0x0215, + QTN_TLV_ID_STA_BASIC_COUNTERS = 0x0300, + QTN_TLV_ID_STA_GENERIC_INFO = 0x0301, + QTN_TLV_ID_KEY = 0x0302, + QTN_TLV_ID_SEQ = 0x0303, + QTN_TLV_ID_CRYPTO = 0x0304, + QTN_TLV_ID_IE_SET = 0x0305, +}; + +struct qlink_tlv_hdr { + __le16 type; + __le16 len; + u8 val[0]; +} __packed; + +struct qlink_iface_limit { + __le16 max_num; + __le16 type_mask; +} __packed; + +struct qlink_iface_comb_num { + __le16 iface_comb_num; +} __packed; + +struct qlink_sta_stat_basic_counters { + __le64 rx_bytes; + __le64 tx_bytes; + __le64 rx_beacons; + __le32 rx_packets; + __le32 tx_packets; + __le32 rx_dropped; + __le32 tx_failed; +} __packed; + +enum qlink_sta_info_rate_flags { + QLINK_STA_INFO_RATE_FLAG_INVALID = 0, + QLINK_STA_INFO_RATE_FLAG_HT_MCS = BIT(0), + QLINK_STA_INFO_RATE_FLAG_VHT_MCS = BIT(1), + QLINK_STA_INFO_RATE_FLAG_SHORT_GI = BIT(2), + QLINK_STA_INFO_RATE_FLAG_60G = BIT(3), +}; + +enum qlink_sta_info_rate_bw { + QLINK_STA_INFO_RATE_BW_5 = 0, + QLINK_STA_INFO_RATE_BW_10 = 1, + QLINK_STA_INFO_RATE_BW_20 = 2, + QLINK_STA_INFO_RATE_BW_40 = 3, + QLINK_STA_INFO_RATE_BW_80 = 4, + QLINK_STA_INFO_RATE_BW_160 = 5, +}; + +/** + * struct qlink_sta_info_rate - STA rate statistics + * + * @rate: data rate in Mbps. + * @flags: bitmap of &enum qlink_sta_flags. + * @mcs: 802.11-defined MCS index. + * nss: Number of Spatial Streams. + * @bw: bandwidth, one of &enum qlink_sta_info_rate_bw. + */ +struct qlink_sta_info_rate { + __le16 rate; + u8 flags; + u8 mcs; + u8 nss; + u8 bw; +} __packed; + +struct qlink_sta_info_state { + __le32 mask; + __le32 value; +} __packed; + +#define QLINK_RSSI_OFFSET 120 + +struct qlink_sta_info_generic { + struct qlink_sta_info_state state; + __le32 connected_time; + __le32 inactive_time; + struct qlink_sta_info_rate rx_rate; + struct qlink_sta_info_rate tx_rate; + u8 rssi; + u8 rssi_avg; +} __packed; + +struct qlink_tlv_frag_rts_thr { + struct qlink_tlv_hdr hdr; + __le16 thr; +} __packed; + +struct qlink_tlv_rlimit { + struct qlink_tlv_hdr hdr; + u8 rlimit; +} __packed; + +struct qlink_tlv_cclass { + struct qlink_tlv_hdr hdr; + u8 cclass; +} __packed; + +enum qlink_dfs_state { + QLINK_DFS_USABLE, + QLINK_DFS_UNAVAILABLE, + QLINK_DFS_AVAILABLE, +}; + +enum qlink_channel_flags { + QLINK_CHAN_DISABLED = BIT(0), + QLINK_CHAN_NO_IR = BIT(1), + QLINK_CHAN_RADAR = BIT(3), + QLINK_CHAN_NO_HT40PLUS = BIT(4), + QLINK_CHAN_NO_HT40MINUS = BIT(5), + QLINK_CHAN_NO_OFDM = BIT(6), + QLINK_CHAN_NO_80MHZ = BIT(7), + QLINK_CHAN_NO_160MHZ = BIT(8), + QLINK_CHAN_INDOOR_ONLY = BIT(9), + QLINK_CHAN_IR_CONCURRENT = BIT(10), + QLINK_CHAN_NO_20MHZ = BIT(11), + QLINK_CHAN_NO_10MHZ = BIT(12), +}; + +struct qlink_tlv_channel { + struct qlink_tlv_hdr hdr; + __le16 hw_value; + __le16 center_freq; + __le32 flags; + u8 band; + u8 max_antenna_gain; + u8 max_power; + u8 max_reg_power; + __le32 dfs_cac_ms; + u8 dfs_state; + u8 beacon_found; + u8 rsvd[2]; +} __packed; + +#define QLINK_MAX_NR_CIPHER_SUITES 5 +#define QLINK_MAX_NR_AKM_SUITES 2 + +struct qlink_auth_encr { + __le32 wpa_versions; + __le32 cipher_group; + __le32 n_ciphers_pairwise; + __le32 ciphers_pairwise[QLINK_MAX_NR_CIPHER_SUITES]; + __le32 n_akm_suites; + __le32 akm_suites[QLINK_MAX_NR_AKM_SUITES]; + __le16 control_port_ethertype; + u8 auth_type; + u8 privacy; + u8 mfp; + u8 control_port; + u8 control_port_no_encrypt; +} __packed; + +#endif /* _QTN_QLINK_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c new file mode 100644 index 000000000000..49ae652ad9a3 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/nl80211.h> + +#include "qlink_util.h" + +u16 qlink_iface_type_mask_to_nl(u16 qlink_mask) +{ + u16 result = 0; + + if (qlink_mask & QLINK_IFTYPE_AP) + result |= BIT(NL80211_IFTYPE_AP); + + if (qlink_mask & QLINK_IFTYPE_STATION) + result |= BIT(NL80211_IFTYPE_STATION); + + if (qlink_mask & QLINK_IFTYPE_ADHOC) + result |= BIT(NL80211_IFTYPE_ADHOC); + + if (qlink_mask & QLINK_IFTYPE_MONITOR) + result |= BIT(NL80211_IFTYPE_MONITOR); + + if (qlink_mask & QLINK_IFTYPE_WDS) + result |= BIT(NL80211_IFTYPE_WDS); + + return result; +} + +u8 qlink_chan_width_mask_to_nl(u16 qlink_mask) +{ + u8 result = 0; + + if (qlink_mask & QLINK_CHAN_WIDTH_5) + result |= BIT(NL80211_CHAN_WIDTH_5); + + if (qlink_mask & QLINK_CHAN_WIDTH_10) + result |= BIT(NL80211_CHAN_WIDTH_10); + + if (qlink_mask & QLINK_CHAN_WIDTH_20_NOHT) + result |= BIT(NL80211_CHAN_WIDTH_20_NOHT); + + if (qlink_mask & QLINK_CHAN_WIDTH_20) + result |= BIT(NL80211_CHAN_WIDTH_20); + + if (qlink_mask & QLINK_CHAN_WIDTH_40) + result |= BIT(NL80211_CHAN_WIDTH_40); + + if (qlink_mask & QLINK_CHAN_WIDTH_80) + result |= BIT(NL80211_CHAN_WIDTH_80); + + if (qlink_mask & QLINK_CHAN_WIDTH_80P80) + result |= BIT(NL80211_CHAN_WIDTH_80P80); + + if (qlink_mask & QLINK_CHAN_WIDTH_160) + result |= BIT(NL80211_CHAN_WIDTH_160); + + return result; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h new file mode 100644 index 000000000000..90d7d09a6c63 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_QLINK_UTIL_H_ +#define _QTN_FMAC_QLINK_UTIL_H_ + +#include <linux/types.h> +#include <linux/skbuff.h> + +#include "qlink.h" + +static inline void qtnf_cmd_skb_put_action(struct sk_buff *skb, u16 action) +{ + __le16 *buf_ptr; + + buf_ptr = skb_put(skb, sizeof(action)); + *buf_ptr = cpu_to_le16(action); +} + +static inline void +qtnf_cmd_skb_put_buffer(struct sk_buff *skb, const u8 *buf_src, size_t len) +{ + skb_put_data(skb, buf_src, len); +} + +static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb, + u16 tlv_id, const u8 arr[], + size_t arr_len) +{ + struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr) + arr_len); + + hdr->type = cpu_to_le16(tlv_id); + hdr->len = cpu_to_le16(arr_len); + memcpy(hdr->val, arr, arr_len); +} + +static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id, + u8 value) +{ + struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr) + sizeof(value)); + + hdr->type = cpu_to_le16(tlv_id); + hdr->len = cpu_to_le16(sizeof(value)); + *hdr->val = value; +} + +static inline void qtnf_cmd_skb_put_tlv_u16(struct sk_buff *skb, + u16 tlv_id, u16 value) +{ + struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr) + sizeof(value)); + __le16 tmp = cpu_to_le16(value); + + hdr->type = cpu_to_le16(tlv_id); + hdr->len = cpu_to_le16(sizeof(value)); + memcpy(hdr->val, &tmp, sizeof(tmp)); +} + +u16 qlink_iface_type_mask_to_nl(u16 qlink_mask); +u8 qlink_chan_width_mask_to_nl(u16 qlink_mask); + +#endif /* _QTN_FMAC_QLINK_UTIL_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h new file mode 100644 index 000000000000..c4ad40d59085 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_HW_IDS_H_ +#define _QTN_HW_IDS_H_ + +#include <linux/pci_ids.h> + +#define PCIE_VENDOR_ID_QUANTENNA (0x1bb5) + +/* PCIE Device IDs */ + +#define PCIE_DEVICE_ID_QTN_PEARL (0x0008) + +/* FW names */ + +#define QTN_PCI_PEARL_FW_NAME "qtn/fmac_qsr10g.img" + +#endif /* _QTN_HW_IDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c new file mode 100644 index 000000000000..aa106dd0a14b --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "shm_ipc.h" + +#undef pr_fmt +#define pr_fmt(fmt) "qtnfmac shm_ipc: %s: " fmt, __func__ + +static bool qtnf_shm_ipc_has_new_data(struct qtnf_shm_ipc *ipc) +{ + const u32 flags = readl(&ipc->shm_region->headroom.hdr.flags); + + return (flags & QTNF_SHM_IPC_NEW_DATA); +} + +static void qtnf_shm_handle_new_data(struct qtnf_shm_ipc *ipc) +{ + size_t size; + bool rx_buff_ok = true; + struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr; + + shm_reg_hdr = &ipc->shm_region->headroom.hdr; + + size = readw(&shm_reg_hdr->data_len); + + if (unlikely(size == 0 || size > QTN_IPC_MAX_DATA_SZ)) { + pr_err("wrong rx packet size: %zu\n", size); + rx_buff_ok = false; + } else { + memcpy_fromio(ipc->rx_data, ipc->shm_region->data, size); + } + + writel(QTNF_SHM_IPC_ACK, &shm_reg_hdr->flags); + readl(&shm_reg_hdr->flags); /* flush PCIe write */ + + ipc->interrupt.fn(ipc->interrupt.arg); + + if (likely(rx_buff_ok)) { + ipc->rx_packet_count++; + ipc->rx_callback.fn(ipc->rx_callback.arg, ipc->rx_data, size); + } +} + +static void qtnf_shm_ipc_irq_work(struct work_struct *work) +{ + struct qtnf_shm_ipc *ipc = container_of(work, struct qtnf_shm_ipc, + irq_work); + + while (qtnf_shm_ipc_has_new_data(ipc)) + qtnf_shm_handle_new_data(ipc); +} + +static void qtnf_shm_ipc_irq_inbound_handler(struct qtnf_shm_ipc *ipc) +{ + u32 flags; + + flags = readl(&ipc->shm_region->headroom.hdr.flags); + + if (flags & QTNF_SHM_IPC_NEW_DATA) + queue_work(ipc->workqueue, &ipc->irq_work); +} + +static void qtnf_shm_ipc_irq_outbound_handler(struct qtnf_shm_ipc *ipc) +{ + u32 flags; + + if (!READ_ONCE(ipc->waiting_for_ack)) + return; + + flags = readl(&ipc->shm_region->headroom.hdr.flags); + + if (flags & QTNF_SHM_IPC_ACK) { + WRITE_ONCE(ipc->waiting_for_ack, 0); + complete(&ipc->tx_completion); + } +} + +int qtnf_shm_ipc_init(struct qtnf_shm_ipc *ipc, + enum qtnf_shm_ipc_direction direction, + struct qtnf_shm_ipc_region __iomem *shm_region, + struct workqueue_struct *workqueue, + const struct qtnf_shm_ipc_int *interrupt, + const struct qtnf_shm_ipc_rx_callback *rx_callback) +{ + BUILD_BUG_ON(offsetof(struct qtnf_shm_ipc_region, data) != + QTN_IPC_REG_HDR_SZ); + BUILD_BUG_ON(sizeof(struct qtnf_shm_ipc_region) > QTN_IPC_REG_SZ); + + ipc->shm_region = shm_region; + ipc->direction = direction; + ipc->interrupt = *interrupt; + ipc->rx_callback = *rx_callback; + ipc->tx_packet_count = 0; + ipc->rx_packet_count = 0; + ipc->workqueue = workqueue; + ipc->waiting_for_ack = 0; + ipc->tx_timeout_count = 0; + + switch (direction) { + case QTNF_SHM_IPC_OUTBOUND: + ipc->irq_handler = qtnf_shm_ipc_irq_outbound_handler; + break; + case QTNF_SHM_IPC_INBOUND: + ipc->irq_handler = qtnf_shm_ipc_irq_inbound_handler; + break; + default: + return -EINVAL; + } + + INIT_WORK(&ipc->irq_work, qtnf_shm_ipc_irq_work); + init_completion(&ipc->tx_completion); + + return 0; +} + +void qtnf_shm_ipc_free(struct qtnf_shm_ipc *ipc) +{ + complete_all(&ipc->tx_completion); +} + +int qtnf_shm_ipc_send(struct qtnf_shm_ipc *ipc, const u8 *buf, size_t size) +{ + int ret = 0; + struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr; + + shm_reg_hdr = &ipc->shm_region->headroom.hdr; + + if (unlikely(size > QTN_IPC_MAX_DATA_SZ)) + return -E2BIG; + + ipc->tx_packet_count++; + + writew(size, &shm_reg_hdr->data_len); + memcpy_toio(ipc->shm_region->data, buf, size); + + /* sync previous writes before proceeding */ + dma_wmb(); + + WRITE_ONCE(ipc->waiting_for_ack, 1); + + /* sync previous memory write before announcing new data ready */ + wmb(); + + writel(QTNF_SHM_IPC_NEW_DATA, &shm_reg_hdr->flags); + readl(&shm_reg_hdr->flags); /* flush PCIe write */ + + ipc->interrupt.fn(ipc->interrupt.arg); + + if (!wait_for_completion_timeout(&ipc->tx_completion, + QTN_SHM_IPC_ACK_TIMEOUT)) { + ret = -ETIMEDOUT; + ipc->tx_timeout_count++; + pr_err("TX ACK timeout\n"); + } + + /* now we're not waiting for ACK even in case of timeout */ + WRITE_ONCE(ipc->waiting_for_ack, 0); + + return ret; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h new file mode 100644 index 000000000000..453dd6477b12 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_SHM_IPC_H_ +#define _QTN_FMAC_SHM_IPC_H_ + +#include <linux/workqueue.h> +#include <linux/completion.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> + +#include "shm_ipc_defs.h" + +#define QTN_SHM_IPC_ACK_TIMEOUT (2 * HZ) + +struct qtnf_shm_ipc_int { + void (*fn)(void *arg); + void *arg; +}; + +struct qtnf_shm_ipc_rx_callback { + void (*fn)(void *arg, const u8 *buf, size_t len); + void *arg; +}; + +enum qtnf_shm_ipc_direction { + QTNF_SHM_IPC_OUTBOUND = BIT(0), + QTNF_SHM_IPC_INBOUND = BIT(1), +}; + +struct qtnf_shm_ipc { + struct qtnf_shm_ipc_region __iomem *shm_region; + enum qtnf_shm_ipc_direction direction; + size_t tx_packet_count; + size_t rx_packet_count; + + size_t tx_timeout_count; + + u8 waiting_for_ack; + + u8 rx_data[QTN_IPC_MAX_DATA_SZ] __aligned(sizeof(u32)); + + struct qtnf_shm_ipc_int interrupt; + struct qtnf_shm_ipc_rx_callback rx_callback; + + void (*irq_handler)(struct qtnf_shm_ipc *ipc); + + struct workqueue_struct *workqueue; + struct work_struct irq_work; + struct completion tx_completion; +}; + +int qtnf_shm_ipc_init(struct qtnf_shm_ipc *ipc, + enum qtnf_shm_ipc_direction direction, + struct qtnf_shm_ipc_region __iomem *shm_region, + struct workqueue_struct *workqueue, + const struct qtnf_shm_ipc_int *interrupt, + const struct qtnf_shm_ipc_rx_callback *rx_callback); +void qtnf_shm_ipc_free(struct qtnf_shm_ipc *ipc); +int qtnf_shm_ipc_send(struct qtnf_shm_ipc *ipc, const u8 *buf, size_t size); + +static inline void qtnf_shm_ipc_irq_handler(struct qtnf_shm_ipc *ipc) +{ + ipc->irq_handler(ipc); +} + +#endif /* _QTN_FMAC_SHM_IPC_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h new file mode 100644 index 000000000000..95a5f89a8b1a --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_SHM_IPC_DEFS_H_ +#define _QTN_FMAC_SHM_IPC_DEFS_H_ + +#include <linux/types.h> + +#define QTN_IPC_REG_HDR_SZ (32) +#define QTN_IPC_REG_SZ (4096) +#define QTN_IPC_MAX_DATA_SZ (QTN_IPC_REG_SZ - QTN_IPC_REG_HDR_SZ) + +enum qtnf_shm_ipc_region_flags { + QTNF_SHM_IPC_NEW_DATA = BIT(0), + QTNF_SHM_IPC_ACK = BIT(1), +}; + +struct qtnf_shm_ipc_region_header { + __le32 flags; + __le16 data_len; +} __packed; + +union qtnf_shm_ipc_region_headroom { + struct qtnf_shm_ipc_region_header hdr; + u8 headroom[QTN_IPC_REG_HDR_SZ]; +} __packed; + +struct qtnf_shm_ipc_region { + union qtnf_shm_ipc_region_headroom headroom; + u8 data[QTN_IPC_MAX_DATA_SZ]; +} __packed; + +#endif /* _QTN_FMAC_SHM_IPC_DEFS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/trans.c b/drivers/net/wireless/quantenna/qtnfmac/trans.c new file mode 100644 index 000000000000..ccddfebc508a --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/trans.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include <linux/types.h> +#include <linux/export.h> +#include <linux/slab.h> + +#include "core.h" +#include "commands.h" +#include "event.h" +#include "bus.h" + +#define QTNF_DEF_SYNC_CMD_TIMEOUT (5 * HZ) + +int qtnf_trans_send_cmd_with_resp(struct qtnf_bus *bus, struct sk_buff *cmd_skb, + struct sk_buff **response_skb) +{ + struct qtnf_cmd_ctl_node *ctl_node = &bus->trans.curr_cmd; + struct qlink_cmd *cmd = (void *)cmd_skb->data; + int ret = 0; + long status; + bool resp_not_handled = true; + struct sk_buff *resp_skb = NULL; + + if (unlikely(!response_skb)) + return -EFAULT; + + spin_lock(&ctl_node->resp_lock); + ctl_node->seq_num++; + cmd->seq_num = cpu_to_le16(ctl_node->seq_num); + WARN(ctl_node->resp_skb, "qtnfmac: response skb not empty\n"); + ctl_node->waiting_for_resp = true; + spin_unlock(&ctl_node->resp_lock); + + ret = qtnf_bus_control_tx(bus, cmd_skb); + dev_kfree_skb(cmd_skb); + + if (unlikely(ret)) + goto out; + + status = wait_for_completion_interruptible_timeout( + &ctl_node->cmd_resp_completion, + QTNF_DEF_SYNC_CMD_TIMEOUT); + + spin_lock(&ctl_node->resp_lock); + resp_not_handled = ctl_node->waiting_for_resp; + resp_skb = ctl_node->resp_skb; + ctl_node->resp_skb = NULL; + ctl_node->waiting_for_resp = false; + spin_unlock(&ctl_node->resp_lock); + + if (unlikely(status <= 0)) { + if (status == 0) { + ret = -ETIMEDOUT; + pr_err("response timeout\n"); + } else { + ret = -EINTR; + pr_debug("interrupted\n"); + } + } + + if (unlikely(!resp_skb || resp_not_handled)) { + if (!ret) + ret = -EFAULT; + + goto out; + } + + ret = 0; + *response_skb = resp_skb; + +out: + if (unlikely(resp_skb && resp_not_handled)) + dev_kfree_skb(resp_skb); + + return ret; +} + +static void qtnf_trans_signal_cmdresp(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_cmd_ctl_node *ctl_node = &bus->trans.curr_cmd; + const struct qlink_resp *resp = (const struct qlink_resp *)skb->data; + const u16 recvd_seq_num = le16_to_cpu(resp->seq_num); + + spin_lock(&ctl_node->resp_lock); + + if (unlikely(!ctl_node->waiting_for_resp)) { + pr_err("unexpected response\n"); + goto out_err; + } + + if (unlikely(recvd_seq_num != ctl_node->seq_num)) { + pr_err("seq num mismatch\n"); + goto out_err; + } + + ctl_node->resp_skb = skb; + ctl_node->waiting_for_resp = false; + + spin_unlock(&ctl_node->resp_lock); + + complete(&ctl_node->cmd_resp_completion); + return; + +out_err: + spin_unlock(&ctl_node->resp_lock); + dev_kfree_skb(skb); +} + +static int qtnf_trans_event_enqueue(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_qlink_transport *trans = &bus->trans; + + if (likely(skb_queue_len(&trans->event_queue) < + trans->event_queue_max_len)) { + skb_queue_tail(&trans->event_queue, skb); + queue_work(bus->workqueue, &bus->event_work); + } else { + pr_warn("event dropped due to queue overflow\n"); + dev_kfree_skb(skb); + return -1; + } + + return 0; +} + +void qtnf_trans_init(struct qtnf_bus *bus) +{ + struct qtnf_qlink_transport *trans = &bus->trans; + + init_completion(&trans->curr_cmd.cmd_resp_completion); + spin_lock_init(&trans->curr_cmd.resp_lock); + + spin_lock(&trans->curr_cmd.resp_lock); + trans->curr_cmd.seq_num = 0; + trans->curr_cmd.waiting_for_resp = false; + trans->curr_cmd.resp_skb = NULL; + spin_unlock(&trans->curr_cmd.resp_lock); + + /* Init event handling related fields */ + skb_queue_head_init(&trans->event_queue); + trans->event_queue_max_len = QTNF_MAX_EVENT_QUEUE_LEN; +} + +static void qtnf_trans_free_events(struct qtnf_bus *bus) +{ + struct sk_buff_head *event_queue = &bus->trans.event_queue; + struct sk_buff *current_event_skb = skb_dequeue(event_queue); + + while (current_event_skb) { + dev_kfree_skb_any(current_event_skb); + current_event_skb = skb_dequeue(event_queue); + } +} + +void qtnf_trans_free(struct qtnf_bus *bus) +{ + if (!bus) { + pr_err("invalid bus pointer\n"); + return; + } + + qtnf_trans_free_events(bus); +} + +int qtnf_trans_handle_rx_ctl_packet(struct qtnf_bus *bus, struct sk_buff *skb) +{ + const struct qlink_msg_header *header = (void *)skb->data; + int ret = -1; + + if (unlikely(skb->len < sizeof(*header))) { + pr_warn("packet is too small: %u\n", skb->len); + dev_kfree_skb(skb); + return -EINVAL; + } + + if (unlikely(skb->len != le16_to_cpu(header->len))) { + pr_warn("cmd reply length mismatch: %u != %u\n", + skb->len, le16_to_cpu(header->len)); + dev_kfree_skb(skb); + return -EFAULT; + } + + switch (le16_to_cpu(header->type)) { + case QLINK_MSG_TYPE_CMDRSP: + if (unlikely(skb->len < sizeof(struct qlink_cmd))) { + pr_warn("cmd reply too short: %u\n", skb->len); + dev_kfree_skb(skb); + break; + } + + qtnf_trans_signal_cmdresp(bus, skb); + break; + case QLINK_MSG_TYPE_EVENT: + if (unlikely(skb->len < sizeof(struct qlink_event))) { + pr_warn("event too short: %u\n", skb->len); + dev_kfree_skb(skb); + break; + } + + ret = qtnf_trans_event_enqueue(bus, skb); + break; + default: + pr_warn("unknown packet type: %x\n", le16_to_cpu(header->type)); + dev_kfree_skb(skb); + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(qtnf_trans_handle_rx_ctl_packet); diff --git a/drivers/net/wireless/quantenna/qtnfmac/trans.h b/drivers/net/wireless/quantenna/qtnfmac/trans.h new file mode 100644 index 000000000000..9a473e07af0f --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/trans.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#ifndef _QTN_FMAC_TRANS_H_ +#define _QTN_FMAC_TRANS_H_ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/mutex.h> + +#include "qlink.h" + +#define QTNF_CMD_FLAG_RESP_REQ BIT(0) + +#define QTNF_MAX_CMD_BUF_SIZE 2048 +#define QTNF_DEF_CMD_HROOM 4 + +struct qtnf_bus; + +struct qtnf_cmd_ctl_node { + struct completion cmd_resp_completion; + struct sk_buff *resp_skb; + u16 seq_num; + bool waiting_for_resp; + spinlock_t resp_lock; /* lock for resp_skb & waiting_for_resp changes */ +}; + +struct qtnf_qlink_transport { + struct qtnf_cmd_ctl_node curr_cmd; + struct sk_buff_head event_queue; + size_t event_queue_max_len; +}; + +void qtnf_trans_init(struct qtnf_bus *bus); +void qtnf_trans_free(struct qtnf_bus *bus); + +int qtnf_trans_send_next_cmd(struct qtnf_bus *bus); +int qtnf_trans_handle_rx_ctl_packet(struct qtnf_bus *bus, struct sk_buff *skb); +int qtnf_trans_send_cmd_with_resp(struct qtnf_bus *bus, + struct sk_buff *cmd_skb, + struct sk_buff **response_skb); + +#endif /* _QTN_FMAC_TRANS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/util.c b/drivers/net/wireless/quantenna/qtnfmac/util.c new file mode 100644 index 000000000000..ed38e87471bf --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/util.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + */ + +#include "util.h" + +void qtnf_sta_list_init(struct qtnf_sta_list *list) +{ + if (unlikely(!list)) + return; + + INIT_LIST_HEAD(&list->head); + atomic_set(&list->size, 0); +} + +struct qtnf_sta_node *qtnf_sta_list_lookup(struct qtnf_sta_list *list, + const u8 *mac) +{ + struct qtnf_sta_node *node; + + if (unlikely(!mac)) + return NULL; + + list_for_each_entry(node, &list->head, list) { + if (ether_addr_equal(node->mac_addr, mac)) + return node; + } + + return NULL; +} + +struct qtnf_sta_node *qtnf_sta_list_lookup_index(struct qtnf_sta_list *list, + size_t index) +{ + struct qtnf_sta_node *node; + + if (qtnf_sta_list_size(list) <= index) + return NULL; + + list_for_each_entry(node, &list->head, list) { + if (index-- == 0) + return node; + } + + return NULL; +} + +struct qtnf_sta_node *qtnf_sta_list_add(struct qtnf_sta_list *list, + const u8 *mac) +{ + struct qtnf_sta_node *node; + + if (unlikely(!mac)) + return NULL; + + node = qtnf_sta_list_lookup(list, mac); + + if (node) + goto done; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (unlikely(!node)) + goto done; + + ether_addr_copy(node->mac_addr, mac); + list_add_tail(&node->list, &list->head); + atomic_inc(&list->size); + +done: + return node; +} + +bool qtnf_sta_list_del(struct qtnf_sta_list *list, const u8 *mac) +{ + struct qtnf_sta_node *node; + bool ret = false; + + node = qtnf_sta_list_lookup(list, mac); + + if (node) { + list_del(&node->list); + atomic_dec(&list->size); + kfree(node); + ret = true; + } + + return ret; +} + +void qtnf_sta_list_free(struct qtnf_sta_list *list) +{ + struct qtnf_sta_node *node, *tmp; + + atomic_set(&list->size, 0); + + list_for_each_entry_safe(node, tmp, &list->head, list) { + list_del(&node->list); + kfree(node); + } + + INIT_LIST_HEAD(&list->head); +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/util.h b/drivers/net/wireless/quantenna/qtnfmac/util.h new file mode 100644 index 000000000000..0359eae8c24b --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/util.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 Quantenna Communications + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QTNFMAC_UTIL_H +#define QTNFMAC_UTIL_H + +#include <linux/kernel.h> +#include "core.h" + +void qtnf_sta_list_init(struct qtnf_sta_list *list); + +struct qtnf_sta_node *qtnf_sta_list_lookup(struct qtnf_sta_list *list, + const u8 *mac); +struct qtnf_sta_node *qtnf_sta_list_lookup_index(struct qtnf_sta_list *list, + size_t index); +struct qtnf_sta_node *qtnf_sta_list_add(struct qtnf_sta_list *list, + const u8 *mac); +bool qtnf_sta_list_del(struct qtnf_sta_list *list, const u8 *mac); + +void qtnf_sta_list_free(struct qtnf_sta_list *list); + +static inline size_t qtnf_sta_list_size(const struct qtnf_sta_list *list) +{ + return atomic_read(&list->size); +} + +static inline bool qtnf_sta_list_empty(const struct qtnf_sta_list *list) +{ + return list_empty(&list->head); +} + +#endif /* QTNFMAC_UTIL_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 19874439ac40..0bc8b0249c57 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -77,10 +77,11 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -103,9 +104,11 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + value = rt2x00_get_field32(reg, BBPCSR_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -138,7 +141,7 @@ static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); @@ -202,7 +205,7 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); return rt2x00_get_field32(reg, GPIOCSR_VAL0); } @@ -215,7 +218,7 @@ static void rt2400pci_brightness_set(struct led_classdev *led_cdev, unsigned int enabled = brightness != LED_OFF; u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) rt2x00_set_field32(®, LEDCSR_LINK, enabled); @@ -233,7 +236,7 @@ static int rt2400pci_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); rt2x00_set_field32(®, LEDCSR_ON_PERIOD, *delay_on); rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, *delay_off); rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg); @@ -266,7 +269,7 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev, * Note that the version error will always be dropped * since there is no filter for it at this time. */ - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, @@ -295,14 +298,14 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, * Enable beacon config */ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); - rt2x00mmio_register_read(rt2x00dev, BCNCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCNCSR1); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00mmio_register_write(rt2x00dev, BCNCSR1, reg); /* * Enable synchronisation. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); } @@ -330,35 +333,35 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, if (changed & BSS_CHANGED_ERP_PREAMBLE) { preamble_mask = erp->short_preamble << 3; - rt2x00mmio_register_read(rt2x00dev, TXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR1); rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x1ff); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0x13a); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR1, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR2); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00mmio_register_write(rt2x00dev, ARCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR3); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00mmio_register_write(rt2x00dev, ARCSR3, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR4); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00mmio_register_write(rt2x00dev, ARCSR4, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR5); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, @@ -370,23 +373,23 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00mmio_register_write(rt2x00dev, ARCSR1, erp->basic_rates); if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); - rt2x00mmio_register_read(rt2x00dev, CSR18, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR18); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); rt2x00mmio_register_write(rt2x00dev, CSR18, reg); - rt2x00mmio_register_read(rt2x00dev, CSR19, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR19); rt2x00_set_field32(®, CSR19_DIFS, erp->difs); rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); rt2x00mmio_register_write(rt2x00dev, CSR19, reg); } if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00mmio_register_read(rt2x00dev, CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR12); rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, @@ -408,8 +411,8 @@ static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev, BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || ant->tx == ANTENNA_SW_DIVERSITY); - rt2400pci_bbp_read(rt2x00dev, 4, &r4); - rt2400pci_bbp_read(rt2x00dev, 1, &r1); + r4 = rt2400pci_bbp_read(rt2x00dev, 4); + r1 = rt2400pci_bbp_read(rt2x00dev, 1); /* * Configure the TX antenna. @@ -495,7 +498,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * Clear false CRC during channel switch. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, &rf->rf1); + rf->rf1 = rt2x00mmio_register_read(rt2x00dev, CNT0); } static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) @@ -508,7 +511,7 @@ static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_LONG_RETRY, libconf->conf->long_frame_max_tx_count); rt2x00_set_field32(®, CSR11_SHORT_RETRY, @@ -525,7 +528,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, @@ -538,7 +541,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR20_AUTOWAKE, 1); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } else { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } @@ -566,7 +569,7 @@ static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_CWMIN, cw_min); rt2x00_set_field32(®, CSR11_CWMAX, cw_max); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); @@ -584,13 +587,13 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2400pci_bbp_read(rt2x00dev, 39, &bbp); + bbp = rt2400pci_bbp_read(rt2x00dev, 39); qual->false_cca = bbp; } @@ -639,12 +642,12 @@ static void rt2400pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); @@ -662,17 +665,17 @@ static void rt2400pci_kick_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; @@ -690,17 +693,17 @@ static void rt2400pci_stop_queue(struct data_queue *queue) case QID_AC_VO: case QID_AC_VI: case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_ABORT, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); @@ -725,11 +728,11 @@ static bool rt2400pci_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || rt2x00_get_field32(word, TXD_W0_VALID)); @@ -743,19 +746,19 @@ static void rt2400pci_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 2, &word); + word = rt2x00_desc_read(entry_priv->desc, 2); rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); rt2x00_desc_write(entry_priv->desc, 2, word); - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_desc_write(entry_priv->desc, 0, word); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_desc_write(entry_priv->desc, 0, word); @@ -770,7 +773,7 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) /* * Initialize registers. */ - rt2x00mmio_register_read(rt2x00dev, TXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR2); rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size); rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit); rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->atim->limit); @@ -778,36 +781,36 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, TXCSR2, reg); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR3); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR3, reg); entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR5); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR5, reg); entry_priv = rt2x00dev->atim->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR4); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR4, reg); entry_priv = rt2x00dev->bcn->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR6, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR6); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR6, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR1); rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00mmio_register_write(rt2x00dev, RXCSR1, reg); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, RXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR2); rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, RXCSR2, reg); @@ -824,18 +827,18 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, PSCSR2, 0x00023f20); rt2x00mmio_register_write(rt2x00dev, PSCSR3, 0x00000002); - rt2x00mmio_register_read(rt2x00dev, TIMECSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TIMECSR); rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); rt2x00mmio_register_write(rt2x00dev, TIMECSR, reg); - rt2x00mmio_register_read(rt2x00dev, CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR9); rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, (rt2x00dev->rx->data_size / 128)); rt2x00mmio_register_write(rt2x00dev, CSR9, reg); - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); @@ -848,14 +851,14 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, CNT3, 0x3f080000); - rt2x00mmio_register_read(rt2x00dev, ARCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR0); rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA0, 133); rt2x00_set_field32(®, ARCSR0_AR_BBP_ID0, 134); rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA1, 136); rt2x00_set_field32(®, ARCSR0_AR_BBP_ID1, 135); rt2x00mmio_register_write(rt2x00dev, ARCSR0, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR3); rt2x00_set_field32(®, RXCSR3_BBP_ID0, 3); /* Tx power.*/ rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, RXCSR3_BBP_ID1, 32); /* Signal */ @@ -872,24 +875,24 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, MACCSR0, 0x00217223); rt2x00mmio_register_write(rt2x00dev, MACCSR1, 0x00235518); - rt2x00mmio_register_read(rt2x00dev, MACCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MACCSR2); rt2x00_set_field32(®, MACCSR2_DELAY, 64); rt2x00mmio_register_write(rt2x00dev, MACCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, RALINKCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RALINKCSR); rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 154); rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA1, 0); rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID1, 154); rt2x00mmio_register_write(rt2x00dev, RALINKCSR, reg); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, CSR1_BBP_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 0); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); @@ -899,8 +902,8 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); - rt2x00mmio_register_read(rt2x00dev, CNT4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); + reg = rt2x00mmio_register_read(rt2x00dev, CNT4); return 0; } @@ -911,7 +914,7 @@ static int rt2400pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2400pci_bbp_read(rt2x00dev, 0, &value); + value = rt2400pci_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -947,7 +950,7 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) rt2400pci_bbp_write(rt2x00dev, 31, 0x00); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -974,7 +977,7 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); } @@ -984,7 +987,7 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, */ spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); @@ -1037,7 +1040,7 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, put_to_sleep = (state != STATE_AWAKE); - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); @@ -1050,7 +1053,7 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®2); + reg2 = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); if (bbp_state == state && rf_state == state) @@ -1110,16 +1113,16 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, txdesc->length); rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, txdesc->length); rt2x00_desc_write(txd, 2, word); - rt2x00_desc_read(txd, 3, &word); + word = rt2x00_desc_read(txd, 3); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1); @@ -1128,7 +1131,7 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1); rt2x00_desc_write(txd, 3, word); - rt2x00_desc_read(txd, 4, &word); + word = rt2x00_desc_read(txd, 4); rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, txdesc->u.plcp.length_low); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8); @@ -1144,7 +1147,7 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, * the device, whereby the device may take hold of the TXD before we * finished updating it. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1180,7 +1183,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); @@ -1225,10 +1228,10 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, u32 rx_low; u32 rx_high; - rt2x00_desc_read(entry_priv->desc, 0, &word0); - rt2x00_desc_read(entry_priv->desc, 2, &word2); - rt2x00_desc_read(entry_priv->desc, 3, &word3); - rt2x00_desc_read(entry_priv->desc, 4, &word4); + word0 = rt2x00_desc_read(entry_priv->desc, 0); + word2 = rt2x00_desc_read(entry_priv->desc, 2); + word3 = rt2x00_desc_read(entry_priv->desc, 3); + word4 = rt2x00_desc_read(entry_priv->desc, 4); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1282,7 +1285,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1320,7 +1323,7 @@ static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1345,7 +1348,7 @@ static void rt2400pci_txstatus_tasklet(unsigned long data) if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); @@ -1381,7 +1384,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) * Get the interrupt sources & saved to local variable. * Write register value back to clear pending interrupts. */ - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); if (!reg) @@ -1419,7 +1422,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); reg |= mask; rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1440,7 +1443,7 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) u16 word; u8 *mac; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom.data = rt2x00dev; eeprom.register_read = rt2400pci_eepromregister_read; @@ -1461,7 +1464,7 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_err(rt2x00dev, "Invalid EEPROM data detected\n"); return -EINVAL; @@ -1479,13 +1482,13 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00mmio_register_read(rt2x00dev, CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR0); rt2x00_set_chip(rt2x00dev, RT2460, value, rt2x00_get_field32(reg, CSR0_REVISION)); @@ -1630,7 +1633,7 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); rt2x00_set_field32(®, GPIOCSR_DIR0, 1); rt2x00mmio_register_write(rt2x00dev, GPIOCSR, reg); @@ -1692,9 +1695,9 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw, u64 tsf; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR17, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR17); tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; - rt2x00mmio_register_read(rt2x00dev, CSR16, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR16); tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); return tsf; @@ -1705,7 +1708,7 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) struct rt2x00_dev *rt2x00dev = hw->priv; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR15, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR15); return rt2x00_get_field32(reg, CSR15_BEACON_SENT); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index 791434de8052..1ff5434798ec 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -77,10 +77,11 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -103,9 +104,11 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + value = rt2x00_get_field32(reg, BBPCSR_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -138,7 +141,7 @@ static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); @@ -202,7 +205,7 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); return rt2x00_get_field32(reg, GPIOCSR_VAL0); } @@ -215,7 +218,7 @@ static void rt2500pci_brightness_set(struct led_classdev *led_cdev, unsigned int enabled = brightness != LED_OFF; u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) rt2x00_set_field32(®, LEDCSR_LINK, enabled); @@ -233,7 +236,7 @@ static int rt2500pci_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); rt2x00_set_field32(®, LEDCSR_ON_PERIOD, *delay_on); rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, *delay_off); rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg); @@ -267,7 +270,7 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, @@ -300,7 +303,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, * Enable beacon config */ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); - rt2x00mmio_register_read(rt2x00dev, BCNCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCNCSR1); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, queue->cw_min); rt2x00mmio_register_write(rt2x00dev, BCNCSR1, reg); @@ -308,7 +311,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); } @@ -335,35 +338,35 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, if (changed & BSS_CHANGED_ERP_PREAMBLE) { preamble_mask = erp->short_preamble << 3; - rt2x00mmio_register_read(rt2x00dev, TXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR1); rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x162); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0xa2); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR1, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR2); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00mmio_register_write(rt2x00dev, ARCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR3); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00mmio_register_write(rt2x00dev, ARCSR3, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR4); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00mmio_register_write(rt2x00dev, ARCSR4, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR5); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, @@ -375,23 +378,23 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00mmio_register_write(rt2x00dev, ARCSR1, erp->basic_rates); if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); - rt2x00mmio_register_read(rt2x00dev, CSR18, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR18); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); rt2x00mmio_register_write(rt2x00dev, CSR18, reg); - rt2x00mmio_register_read(rt2x00dev, CSR19, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR19); rt2x00_set_field32(®, CSR19_DIFS, erp->difs); rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); rt2x00mmio_register_write(rt2x00dev, CSR19, reg); } if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00mmio_register_read(rt2x00dev, CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR12); rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, @@ -415,9 +418,9 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || ant->tx == ANTENNA_SW_DIVERSITY); - rt2x00mmio_register_read(rt2x00dev, BBPCSR1, ®); - rt2500pci_bbp_read(rt2x00dev, 14, &r14); - rt2500pci_bbp_read(rt2x00dev, 2, &r2); + reg = rt2x00mmio_register_read(rt2x00dev, BBPCSR1); + r14 = rt2500pci_bbp_read(rt2x00dev, 14); + r2 = rt2500pci_bbp_read(rt2x00dev, 2); /* * Configure the TX antenna. @@ -538,7 +541,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * Clear false CRC during channel switch. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, &rf->rf1); + rf->rf1 = rt2x00mmio_register_read(rt2x00dev, CNT0); } static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, @@ -546,7 +549,7 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, { u32 rf3; - rt2x00_rf_read(rt2x00dev, 3, &rf3); + rf3 = rt2x00_rf_read(rt2x00dev, 3); rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2500pci_rf_write(rt2x00dev, 3, rf3); } @@ -556,7 +559,7 @@ static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_LONG_RETRY, libconf->conf->long_frame_max_tx_count); rt2x00_set_field32(®, CSR11_SHORT_RETRY, @@ -573,7 +576,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, @@ -586,7 +589,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR20_AUTOWAKE, 1); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } else { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } @@ -622,13 +625,13 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2x00mmio_register_read(rt2x00dev, CNT3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT3); qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); } @@ -728,12 +731,12 @@ static void rt2500pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); @@ -751,17 +754,17 @@ static void rt2500pci_kick_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; @@ -779,17 +782,17 @@ static void rt2500pci_stop_queue(struct data_queue *queue) case QID_AC_VO: case QID_AC_VI: case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_ABORT, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); @@ -814,11 +817,11 @@ static bool rt2500pci_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || rt2x00_get_field32(word, TXD_W0_VALID)); @@ -832,15 +835,15 @@ static void rt2500pci_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_desc_write(entry_priv->desc, 0, word); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_desc_write(entry_priv->desc, 0, word); @@ -855,7 +858,7 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) /* * Initialize registers. */ - rt2x00mmio_register_read(rt2x00dev, TXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR2); rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size); rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit); rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->atim->limit); @@ -863,36 +866,36 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, TXCSR2, reg); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR3); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR3, reg); entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR5); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR5, reg); entry_priv = rt2x00dev->atim->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR4); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR4, reg); entry_priv = rt2x00dev->bcn->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR6, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR6); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR6, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR1); rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00mmio_register_write(rt2x00dev, RXCSR1, reg); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, RXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR2); rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, RXCSR2, reg); @@ -909,13 +912,13 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, PSCSR2, 0x00020002); rt2x00mmio_register_write(rt2x00dev, PSCSR3, 0x00000002); - rt2x00mmio_register_read(rt2x00dev, TIMECSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TIMECSR); rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); rt2x00mmio_register_write(rt2x00dev, TIMECSR, reg); - rt2x00mmio_register_read(rt2x00dev, CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR9); rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, rt2x00dev->rx->data_size / 128); rt2x00mmio_register_write(rt2x00dev, CSR9, reg); @@ -923,11 +926,11 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * Always use CWmin and CWmax set in descriptor. */ - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_CW_SELECT, 0); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); @@ -940,7 +943,7 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, CNT3, 0); - rt2x00mmio_register_read(rt2x00dev, TXCSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR8); rt2x00_set_field32(®, TXCSR8_BBP_ID0, 10); rt2x00_set_field32(®, TXCSR8_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXCSR8_BBP_ID1, 11); @@ -951,28 +954,28 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR8_BBP_ID3_VALID, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR8, reg); - rt2x00mmio_register_read(rt2x00dev, ARTCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARTCSR0); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_1MBS, 112); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_2MBS, 56); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_5_5MBS, 20); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_11MBS, 10); rt2x00mmio_register_write(rt2x00dev, ARTCSR0, reg); - rt2x00mmio_register_read(rt2x00dev, ARTCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARTCSR1); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_6MBS, 45); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_9MBS, 37); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_12MBS, 33); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_18MBS, 29); rt2x00mmio_register_write(rt2x00dev, ARTCSR1, reg); - rt2x00mmio_register_read(rt2x00dev, ARTCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARTCSR2); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_24MBS, 29); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_36MBS, 25); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_48MBS, 25); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_54MBS, 25); rt2x00mmio_register_write(rt2x00dev, ARTCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR3); rt2x00_set_field32(®, RXCSR3_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, RXCSR3_BBP_ID1, 51); /* Rssi */ @@ -983,7 +986,7 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR3_BBP_ID3_VALID, 1); rt2x00mmio_register_write(rt2x00dev, RXCSR3, reg); - rt2x00mmio_register_read(rt2x00dev, PCICSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PCICSR); rt2x00_set_field32(®, PCICSR_BIG_ENDIAN, 0); rt2x00_set_field32(®, PCICSR_RX_TRESHOLD, 0); rt2x00_set_field32(®, PCICSR_TX_TRESHOLD, 3); @@ -1004,11 +1007,11 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, MACCSR0, 0x00213223); rt2x00mmio_register_write(rt2x00dev, MACCSR1, 0x00235518); - rt2x00mmio_register_read(rt2x00dev, MACCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MACCSR2); rt2x00_set_field32(®, MACCSR2_DELAY, 64); rt2x00mmio_register_write(rt2x00dev, MACCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, RALINKCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RALINKCSR); rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 26); rt2x00_set_field32(®, RALINKCSR_AR_BBP_VALID0, 1); @@ -1021,13 +1024,13 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, TXACKCSR0, 0x00000020); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, CSR1_BBP_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 0); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); @@ -1037,8 +1040,8 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); - rt2x00mmio_register_read(rt2x00dev, CNT4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); + reg = rt2x00mmio_register_read(rt2x00dev, CNT4); return 0; } @@ -1049,7 +1052,7 @@ static int rt2500pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500pci_bbp_read(rt2x00dev, 0, &value); + value = rt2500pci_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -1101,7 +1104,7 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) rt2500pci_bbp_write(rt2x00dev, 62, 0x10); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1128,7 +1131,7 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); } @@ -1138,7 +1141,7 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, */ spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); @@ -1190,7 +1193,7 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, put_to_sleep = (state != STATE_AWAKE); - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); @@ -1203,7 +1206,7 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®2); + reg2 = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); if (bbp_state == state && rf_state == state) @@ -1263,18 +1266,18 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W2_AIFS, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W2_CWMIN, entry->queue->cw_min); rt2x00_set_field32(&word, TXD_W2_CWMAX, entry->queue->cw_max); rt2x00_desc_write(txd, 2, word); - rt2x00_desc_read(txd, 3, &word); + word = rt2x00_desc_read(txd, 3); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, @@ -1283,7 +1286,7 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, txdesc->u.plcp.length_high); rt2x00_desc_write(txd, 3, word); - rt2x00_desc_read(txd, 10, &word); + word = rt2x00_desc_read(txd, 10); rt2x00_set_field32(&word, TXD_W10_RTS, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); rt2x00_desc_write(txd, 10, word); @@ -1293,7 +1296,7 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, * the device, whereby the device may take hold of the TXD before we * finished updating it. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1332,7 +1335,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); @@ -1368,8 +1371,8 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, u32 word0; u32 word2; - rt2x00_desc_read(entry_priv->desc, 0, &word0); - rt2x00_desc_read(entry_priv->desc, 2, &word2); + word0 = rt2x00_desc_read(entry_priv->desc, 0); + word2 = rt2x00_desc_read(entry_priv->desc, 2); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1410,7 +1413,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -1448,7 +1451,7 @@ static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1473,7 +1476,7 @@ static void rt2500pci_txstatus_tasklet(unsigned long data) if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); @@ -1509,7 +1512,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) * Get the interrupt sources & saved to local variable. * Write register value back to clear pending interrupts. */ - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); if (!reg) @@ -1547,7 +1550,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); reg |= mask; rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1566,7 +1569,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) u16 word; u8 *mac; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom.data = rt2x00dev; eeprom.register_read = rt2500pci_eepromregister_read; @@ -1587,7 +1590,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -1603,7 +1606,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); @@ -1612,7 +1615,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, DEFAULT_RSSI_OFFSET); @@ -1633,13 +1636,13 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00mmio_register_read(rt2x00dev, CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR0); rt2x00_set_chip(rt2x00dev, RT2560, value, rt2x00_get_field32(reg, CSR0_REVISION)); @@ -1689,14 +1692,14 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Check if the BBP tuning should be enabled. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); /* * Read the RSSI <-> dBm offset information. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); rt2x00dev->rssi_offset = rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); @@ -1955,7 +1958,7 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); rt2x00_set_field32(®, GPIOCSR_DIR0, 1); rt2x00mmio_register_write(rt2x00dev, GPIOCSR, reg); @@ -1991,9 +1994,9 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw, u64 tsf; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR17, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR17); tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; - rt2x00mmio_register_read(rt2x00dev, CSR16, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR16); tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); return tsf; @@ -2004,7 +2007,7 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) struct rt2x00_dev *rt2x00dev = hw->priv; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR15, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR15); return rt2x00_get_field32(reg, CSR15_BEACON_SENT); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 0d2670a56c4c..529e05999abb 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -55,26 +55,24 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * If the csr_mutex is already held then the _lock variants must * be used instead. */ -static void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u16 *value) +static u16 rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le16 reg; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg)); - *value = le16_to_cpu(reg); + return le16_to_cpu(reg); } -static void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u16 *value) +static u16 rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le16 reg; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg), REGISTER_TIMEOUT); - *value = le16_to_cpu(reg); + return le16_to_cpu(reg); } static void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -114,7 +112,7 @@ static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev, unsigned int i; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, offset, reg); + *reg = rt2500usb_register_read_lock(rt2x00dev, offset); if (!rt2x00_get_field16(*reg, field)) return 1; udelay(REGISTER_BUSY_DELAY); @@ -155,10 +153,11 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u16 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -178,12 +177,14 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); if (WAIT_FOR_BBP(rt2x00dev, ®)) - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); + reg = rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7); } - *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); + value = rt2x00_get_field16(reg, PHY_CSR7_DATA); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, @@ -216,14 +217,10 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static u32 _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { - u16 tmp; - - rt2500usb_register_read(rt2x00dev, offset, &tmp); - *value = tmp; + return rt2500usb_register_read(rt2x00dev, offset); } static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -271,7 +268,7 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u16 reg; - rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR19); return rt2x00_get_field16(reg, MAC_CSR19_VAL7); } @@ -284,7 +281,7 @@ static void rt2500usb_brightness_set(struct led_classdev *led_cdev, unsigned int enabled = brightness != LED_OFF; u16 reg; - rt2500usb_register_read(led->rt2x00dev, MAC_CSR20, ®); + reg = rt2500usb_register_read(led->rt2x00dev, MAC_CSR20); if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) rt2x00_set_field16(®, MAC_CSR20_LINK, enabled); @@ -302,7 +299,7 @@ static int rt2500usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u16 reg; - rt2500usb_register_read(led->rt2x00dev, MAC_CSR21, ®); + reg = rt2500usb_register_read(led->rt2x00dev, MAC_CSR21); rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, *delay_on); rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, *delay_off); rt2500usb_register_write(led->rt2x00dev, MAC_CSR21, reg); @@ -356,7 +353,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, */ mask = TXRX_CSR0_KEY_ID.bit_mask; - rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR0); curr_cipher = rt2x00_get_field16(reg, TXRX_CSR0_ALGORITHM); reg &= mask; @@ -395,7 +392,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate * a particular key is valid. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field16(®, TXRX_CSR0_ALGORITHM, crypto->cipher); rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); @@ -421,7 +418,7 @@ static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, @@ -453,7 +450,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, * Enable beacon config */ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); - rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR20); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6); rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2 * (conf->type != NL80211_IFTYPE_STATION)); @@ -462,11 +459,11 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR18); rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, conf->sync); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } @@ -487,7 +484,7 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, u16 reg; if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR10); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); @@ -498,7 +495,7 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, erp->basic_rates); if (changed & BSS_CHANGED_BEACON_INT) { - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR18); rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, erp->beacon_int * 4); rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); @@ -526,10 +523,10 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || ant->tx == ANTENNA_SW_DIVERSITY); - rt2500usb_bbp_read(rt2x00dev, 2, &r2); - rt2500usb_bbp_read(rt2x00dev, 14, &r14); - rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5); - rt2500usb_register_read(rt2x00dev, PHY_CSR6, &csr6); + r2 = rt2500usb_bbp_read(rt2x00dev, 2); + r14 = rt2500usb_bbp_read(rt2x00dev, 14); + csr5 = rt2500usb_register_read(rt2x00dev, PHY_CSR5); + csr6 = rt2500usb_register_read(rt2x00dev, PHY_CSR6); /* * Configure the TX antenna. @@ -629,7 +626,7 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, { u32 rf3; - rt2x00_rf_read(rt2x00dev, 3, &rf3); + rf3 = rt2x00_rf_read(rt2x00dev, 3); rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2500usb_rf_write(rt2x00dev, 3, rf3); } @@ -643,7 +640,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, u16 reg; if (state == STATE_SLEEP) { - rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR18); rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, rt2x00dev->beacon_int - 20); rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP, @@ -656,7 +653,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, MAC_CSR18_AUTO_WAKE, 1); rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); } else { - rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR18); rt2x00_set_field16(®, MAC_CSR18_AUTO_WAKE, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); } @@ -690,13 +687,13 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2500usb_register_read(rt2x00dev, STA_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, STA_CSR0); qual->rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2500usb_register_read(rt2x00dev, STA_CSR3, ®); + reg = rt2500usb_register_read(rt2x00dev, STA_CSR3); qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); } @@ -706,19 +703,19 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev, u16 eeprom; u16 value; - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R24_LOW); rt2500usb_bbp_write(rt2x00dev, 24, value); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R25_LOW); rt2500usb_bbp_write(rt2x00dev, 25, value); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R61_LOW); rt2500usb_bbp_write(rt2x00dev, 61, value); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER); rt2500usb_bbp_write(rt2x00dev, 17, value); @@ -735,12 +732,12 @@ static void rt2500usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); break; case QID_BEACON: - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); @@ -758,12 +755,12 @@ static void rt2500usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); break; case QID_BEACON: - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); @@ -786,54 +783,54 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_vendor_request_sw(rt2x00dev, USB_SINGLE_WRITE, 0x0308, 0x00f0, REGISTER_TIMEOUT); - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111); rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11); - rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 1); rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR5, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR5); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0, 13); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1, 12); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1_VALID, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR5, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR6, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR6); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0, 10); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1, 11); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1_VALID, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR6, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR7, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR7); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0, 7); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1, 6); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1_VALID, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR7, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR8, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR8); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0, 5); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1, 0); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1_VALID, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); @@ -846,14 +843,14 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) return -EBUSY; - rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) { - rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, PHY_CSR2); rt2x00_set_field16(®, PHY_CSR2_LNA, 0); } else { reg = 0; @@ -867,26 +864,26 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2500usb_register_write(rt2x00dev, MAC_CSR15, 0x01ee); rt2500usb_register_write(rt2x00dev, MAC_CSR16, 0x0000); - rt2500usb_register_read(rt2x00dev, MAC_CSR8, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR8); rt2x00_set_field16(®, MAC_CSR8_MAX_FRAME_UNIT, rt2x00dev->rx->data_size); rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field16(®, TXRX_CSR0_ALGORITHM, CIPHER_NONE); rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR18); rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, 90); rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); - rt2500usb_register_read(rt2x00dev, PHY_CSR4, ®); + reg = rt2500usb_register_read(rt2x00dev, PHY_CSR4); rt2x00_set_field16(®, PHY_CSR4_LOW_RF_LE, 1); rt2500usb_register_write(rt2x00dev, PHY_CSR4, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR1); rt2x00_set_field16(®, TXRX_CSR1_AUTO_SEQUENCE, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); @@ -899,7 +896,7 @@ static int rt2500usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2500usb_bbp_read(rt2x00dev, 0, &value); + value = rt2500usb_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -952,7 +949,7 @@ static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev) rt2500usb_bbp_write(rt2x00dev, 75, 0xff); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1018,7 +1015,7 @@ static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2500usb_register_read(rt2x00dev, MAC_CSR17, ®2); + reg2 = rt2500usb_register_read(rt2x00dev, MAC_CSR17); bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE); rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE); if (bbp_state == state && rf_state == state) @@ -1077,7 +1074,7 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); @@ -1095,14 +1092,14 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx); rt2x00_desc_write(txd, 0, word); - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_AIFS, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, @@ -1143,7 +1140,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); @@ -1250,8 +1247,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, /* * It is now safe to read the descriptor on all architectures. */ - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 1, &word1); + word0 = rt2x00_desc_read(rxd, 0); + word1 = rt2x00_desc_read(rxd, 1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1263,8 +1260,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY; if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); - _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->iv[0] = _rt2x00_desc_read(rxd, 2); + rxdesc->iv[1] = _rt2x00_desc_read(rxd, 3); rxdesc->dev_flags |= RXDONE_CRYPTO_IV; /* ICV is located at the end of frame */ @@ -1342,7 +1339,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -1358,7 +1355,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); @@ -1367,7 +1364,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, DEFAULT_RSSI_OFFSET); @@ -1376,7 +1373,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45); rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word); @@ -1387,10 +1384,10 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) * Switch lower vgc bound to current BBP R17 value, * lower the value a bit for better quality. */ - rt2500usb_bbp_read(rt2x00dev, 17, &bbp); + bbp = rt2500usb_bbp_read(rt2x00dev, 17); bbp -= 6; - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40); rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp); @@ -1401,7 +1398,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41); @@ -1409,7 +1406,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r17: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80); @@ -1417,7 +1414,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r24: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50); @@ -1425,7 +1422,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r25: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d); @@ -1445,13 +1442,13 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR0); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); if (((reg & 0xfff0) != 0) || ((reg & 0x0000000f) == 0)) { @@ -1511,7 +1508,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read the RSSI <-> dBm offset information. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); rt2x00dev->rssi_offset = rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); @@ -1776,7 +1773,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR19); rt2x00_set_field16(®, MAC_CSR19_DIR0, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR19, reg); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index d11c7b210e81..6e2e760d98b1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -110,10 +110,10 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -137,9 +137,11 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); + value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, @@ -203,10 +205,11 @@ static void rt2800_rfcsr_write_dccal(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write_bank(rt2x00dev, 7, reg, value); } -static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -232,7 +235,7 @@ static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA_MT7620); + value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA_MT7620); break; default: @@ -247,17 +250,19 @@ static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_RFCSR(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); + value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); break; } mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } -static void rt2800_rfcsr_read_bank(struct rt2x00_dev *rt2x00dev, const u8 bank, - const unsigned int reg, u8 *value) +static u8 rt2800_rfcsr_read_bank(struct rt2x00_dev *rt2x00dev, const u8 bank, + const unsigned int reg) { - rt2800_rfcsr_read(rt2x00dev, (reg | (bank << 6)), value); + return rt2800_rfcsr_read(rt2x00dev, (reg | (bank << 6))); } static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, @@ -405,13 +410,13 @@ static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev, return rt2x00_eeprom_addr(rt2x00dev, index); } -static void rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, - const enum rt2800_eeprom_word word, u16 *data) +static u16 rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word word) { unsigned int index; index = rt2800_eeprom_word_index(rt2x00dev, word); - rt2x00_eeprom_read(rt2x00dev, index, data); + return rt2x00_eeprom_read(rt2x00dev, index); } static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, @@ -423,15 +428,14 @@ static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, rt2x00_eeprom_write(rt2x00dev, index, data); } -static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, - const enum rt2800_eeprom_word array, - unsigned int offset, - u16 *data) +static u16 rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word array, + unsigned int offset) { unsigned int index; index = rt2800_eeprom_word_index(rt2x00dev, array); - rt2x00_eeprom_read(rt2x00dev, index + offset, data); + return rt2x00_eeprom_read(rt2x00dev, index + offset); } static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) @@ -439,7 +443,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) u32 reg; int i, count; - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff); rt2x00_set_field32(®, FRC_WL_ANT_SET, 1); rt2x00_set_field32(®, WLAN_CLK_EN, 0); @@ -454,7 +458,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) * Check PLL_LD & XTAL_RDY. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, CMB_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, CMB_CTRL); if (rt2x00_get_field32(reg, PLL_LD) && rt2x00_get_field32(reg, XTAL_RDY)) break; @@ -477,7 +481,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) count = 0; } - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 0); rt2x00_set_field32(®, WLAN_CLK_EN, 1); rt2x00_set_field32(®, WLAN_RESET, 1); @@ -532,7 +536,7 @@ int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2800_register_read(rt2x00dev, MAC_CSR0); if (reg && reg != ~0) return 0; msleep(1); @@ -553,7 +557,7 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) * before timing out. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) return 0; @@ -570,7 +574,7 @@ void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); @@ -720,7 +724,7 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) { - rt2800_register_read(rt2x00dev, AUX_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, AUX_CTRL); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); rt2800_register_write(rt2x00dev, AUX_CTRL, reg); @@ -739,7 +743,7 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for device to stabilize. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, PBF_SYS_CTRL); if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) break; msleep(1); @@ -781,7 +785,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, /* * Initialize TX Info descriptor */ - rt2x00_desc_read(txwi, 0, &word); + word = rt2x00_desc_read(txwi, 0); rt2x00_set_field32(&word, TXWI_W0_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, @@ -803,7 +807,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); rt2x00_desc_write(txwi, 0, word); - rt2x00_desc_read(txwi, 1, &word); + word = rt2x00_desc_read(txwi, 1); rt2x00_set_field32(&word, TXWI_W1_ACK, test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W1_NSEQ, @@ -843,16 +847,16 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) u8 offset2; if (rt2x00dev->curr_band == NL80211_BAND_2GHZ) { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG); offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0); offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2); offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A); offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0); offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2); offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2); } @@ -881,12 +885,12 @@ void rt2800_process_rxwi(struct queue_entry *entry, __le32 *rxwi = (__le32 *) entry->skb->data; u32 word; - rt2x00_desc_read(rxwi, 0, &word); + word = rt2x00_desc_read(rxwi, 0); rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF); rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT); - rt2x00_desc_read(rxwi, 1, &word); + word = rt2x00_desc_read(rxwi, 1); if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI)) rxdesc->enc_flags |= RX_ENC_FLAG_SHORT_GI; @@ -907,7 +911,7 @@ void rt2800_process_rxwi(struct queue_entry *entry, if (rxdesc->rate_mode == RATE_MODE_CCK) rxdesc->signal &= ~0x8; - rt2x00_desc_read(rxwi, 2, &word); + word = rt2x00_desc_read(rxwi, 2); /* * Convert descriptor AGC value to RSSI value. @@ -968,7 +972,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, * Obtain the status about this packet. */ txdesc.flags = 0; - rt2x00_desc_read(txwi, 0, &word); + word = rt2x00_desc_read(txwi, 0); mcs = rt2x00_get_field32(word, TXWI_W0_MCS); ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU); @@ -1093,7 +1097,7 @@ static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev) /* * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons. */ - rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1); + bssid_dw1 = rt2800_register_read(rt2x00dev, MAC_BSSID_DW1); rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM, bcn_num > 0 ? bcn_num - 1 : 0); rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1); @@ -1112,7 +1116,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); orig_reg = reg; rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1202,7 +1206,7 @@ void rt2800_clear_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &orig_reg); + orig_reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); reg = orig_reg; rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1275,10 +1279,10 @@ int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev) u32 reg; if (rt2x00_rt(rt2x00dev, RT3290)) { - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0); } else { - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); return rt2x00_get_field32(reg, GPIO_CTRL_VAL2); } } @@ -1303,7 +1307,7 @@ static void rt2800_brightness_set(struct led_classdev *led_cdev, /* Check for SoC (SOC devices don't support MCU requests) */ if (rt2x00_is_soc(led->rt2x00dev)) { - rt2800_register_read(led->rt2x00dev, LED_CFG, ®); + reg = rt2800_register_read(led->rt2x00dev, LED_CFG); /* Set LED Polarity */ rt2x00_set_field32(®, LED_CFG_LED_POLAR, polarity); @@ -1392,7 +1396,7 @@ static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev, * The BSS Idx numbers is split in a main value of 3 bits, * and a extended field for adding one additional bit to the value. */ - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7)); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT, (bssidx & 0x8) >> 3); @@ -1410,7 +1414,7 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev, offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); if (crypto->cmd == SET_KEY) { - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); /* @@ -1426,7 +1430,7 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, offset, reg); } else { /* Delete the cipher without touching the bssidx */ - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, 0); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, 0); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0); @@ -1482,7 +1486,7 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, (crypto->cmd == SET_KEY) * crypto->cipher); rt2800_register_write(rt2x00dev, offset, reg); @@ -1548,7 +1552,7 @@ static void rt2800_set_max_psdu_len(struct rt2x00_dev *rt2x00dev) max_psdu = min(drv_data->max_psdu, i); - rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MAX_LEN_CFG); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, max_psdu); rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); } @@ -1640,7 +1644,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); + reg = rt2800_register_read(rt2x00dev, RX_FILTER_CFG); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, @@ -1684,7 +1688,7 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, /* * Enable synchronisation. */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1692,14 +1696,14 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, /* * Tune beacon queue transmit parameters for AP mode */ - rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 0); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 1); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 0); rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); } else { - rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 4); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 2); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); @@ -1818,22 +1822,22 @@ static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev, gf20_mode = gf40_mode = 1; /* Update HT protection config */ - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, mm20_rate); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode); rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM40_PROT_CFG); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, mm40_rate); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode); rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF20_PROT_CFG); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, gf20_rate); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode); rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF40_PROT_CFG); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, gf40_rate); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode); rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); @@ -1845,14 +1849,14 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, u32 reg; if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTO_RSP_CFG); rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, !!erp->short_preamble); rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, erp->cts_protection ? 2 : 0); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); @@ -1865,18 +1869,18 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, } if (changed & BSS_CHANGED_ERP_SLOT) { - rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG); rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); - rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, XIFS_TIME_CFG); rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); } if (changed & BSS_CHANGED_BEACON_INT) { - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, erp->beacon_int * 16); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1893,7 +1897,7 @@ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) u16 eeprom; u8 led_ctrl, led_g_mode, led_r_mode; - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { rt2x00_set_field32(®, GPIO_SWITCH_0, 1); rt2x00_set_field32(®, GPIO_SWITCH_1, 1); @@ -1903,12 +1907,12 @@ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) } rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); - rt2800_register_read(rt2x00dev, LED_CFG, ®); + reg = rt2800_register_read(rt2x00dev, LED_CFG); led_g_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 3 : 0; led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3; if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) || led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ); led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE); if (led_ctrl == 0 || led_ctrl > 0x40) { rt2x00_set_field32(®, LED_CFG_G_LED_MODE, led_g_mode); @@ -1929,14 +1933,14 @@ static void rt2800_set_ant_diversity(struct rt2x00_dev *rt2x00dev, u8 gpio_bit3 = (ant == ANTENNA_A) ? 0 : 1; if (rt2x00_is_pci(rt2x00dev)) { - rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2800_register_read(rt2x00dev, E2PROM_CSR); rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, eesk_pin); rt2800_register_write(rt2x00dev, E2PROM_CSR, reg); } else if (rt2x00_is_usb(rt2x00dev)) rt2800_mcu_request(rt2x00dev, MCU_ANT_SELECT, 0xff, eesk_pin, 0); - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR3, 0); rt2x00_set_field32(®, GPIO_CTRL_VAL3, gpio_bit3); rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); @@ -1948,8 +1952,8 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) u8 r3; u16 eeprom; - rt2800_bbp_read(rt2x00dev, 1, &r1); - rt2800_bbp_read(rt2x00dev, 3, &r3); + r1 = rt2800_bbp_read(rt2x00dev, 1); + r3 = rt2800_bbp_read(rt2x00dev, 3); if (rt2x00_rt(rt2x00dev, RT3572) && rt2x00_has_cap_bt_coexist(rt2x00dev)) @@ -1983,8 +1987,8 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3352) || rt2x00_rt(rt2x00dev, RT3390)) { - rt2800_eeprom_read(rt2x00dev, - EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, + EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY)) rt2800_set_ant_diversity(rt2x00dev, @@ -2027,28 +2031,28 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, short lna_gain; if (libconf->rf.channel <= 14) { - rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_LNA); lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); } else if (libconf->rf.channel <= 64) { - rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_LNA); lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); } else if (libconf->rf.channel <= 128) { if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_EXT_LNA2_A1); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); } } else { if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_EXT_LNA2_A2); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); } @@ -2072,7 +2076,7 @@ static void rt2800_freq_cal_mode1(struct rt2x00_dev *rt2x00dev) freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); freq_offset = min_t(u8, freq_offset, FREQ_OFFSET_BOUND); - rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 17); prev_rfcsr = rfcsr; rt2x00_set_field8(&rfcsr, RFCSR17_CODE, freq_offset); @@ -2174,23 +2178,23 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_K, rf->rf3); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 12); rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1); rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 13); rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2); rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, rt2x00dev->default_ant.rx_chain_num <= 1); @@ -2203,7 +2207,7 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2x00dev->default_ant.tx_chain_num <= 2); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 23); rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); @@ -2220,19 +2224,19 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, } } - rt2800_rfcsr_read(rt2x00dev, 24, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 24); rt2x00_set_field8(&rfcsr, RFCSR24_TX_CALIB, calib_tx); rt2800_rfcsr_write(rt2x00dev, 24, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 31); rt2x00_set_field8(&rfcsr, RFCSR31_RX_CALIB, calib_rx); rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); @@ -2262,7 +2266,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 2); @@ -2270,14 +2274,14 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 5, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 5); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR5_R1, 1); else rt2x00_set_field8(&rfcsr, RFCSR5_R1, 2); rt2800_rfcsr_write(rt2x00dev, 5, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 12); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 3); rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, @@ -2290,7 +2294,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 13); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 3); rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, @@ -2303,7 +2307,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); @@ -2336,7 +2340,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 23); rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); @@ -2366,7 +2370,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 27, 0x00); rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); } else { - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_BIT2, 1); rt2x00_set_field8(&rfcsr, RFCSR7_BIT3, 0); rt2x00_set_field8(&rfcsr, RFCSR7_BIT4, 1); @@ -2399,7 +2403,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 29, 0x9f); } - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR7, 0); if (rf->channel <= 14) rt2x00_set_field32(®, GPIO_CTRL_VAL7, 1); @@ -2407,7 +2411,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, GPIO_CTRL_VAL7, 0); rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); } @@ -2425,12 +2429,12 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, const bool txbf_enabled = false; /* TODO */ /* TODO: use TX{0,1,2}FinePowerControl values from EEPROM */ - rt2800_bbp_read(rt2x00dev, 109, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 109); rt2x00_set_field8(&bbp, BBP109_TX0_POWER, 0); rt2x00_set_field8(&bbp, BBP109_TX1_POWER, 0); rt2800_bbp_write(rt2x00dev, 109, bbp); - rt2800_bbp_read(rt2x00dev, 110, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 110); rt2x00_set_field8(&bbp, BBP110_TX2_POWER, 0); rt2800_bbp_write(rt2x00dev, 110, bbp); @@ -2450,11 +2454,11 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3 & 0xf); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, (rf->rf2 & 0x3)); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_PLL_IDOH, 1); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 1); @@ -2462,7 +2466,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 2); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 53, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 53); if (rf->channel <= 14) { rfcsr = 0; rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER, @@ -2477,7 +2481,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 53, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 55, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 55); if (rf->channel <= 14) { rfcsr = 0; rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER, @@ -2492,7 +2496,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 55, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 54, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 54); if (rf->channel <= 14) { rfcsr = 0; rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER, @@ -2507,7 +2511,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 54, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); @@ -2559,7 +2563,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, /* NOTE: the reference driver does not writes the new value * back to RFCSR 32 */ - rt2800_rfcsr_read(rt2x00dev, 32, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 32); rt2x00_set_field8(&rfcsr, RFCSR32_TX_AGC_FC, txrx_agc_fc); if (rf->channel <= 14) @@ -2568,34 +2572,34 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rfcsr = 0x80; rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, txrx_h20m); rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, txrx_h20m); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); /* Band selection */ - rt2800_rfcsr_read(rt2x00dev, 36, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 36); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 1); else rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 0); rt2800_rfcsr_write(rt2x00dev, 36, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 34, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 34); if (rf->channel <= 14) rfcsr = 0x3c; else rfcsr = 0x20; rt2800_rfcsr_write(rt2x00dev, 34, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 12); if (rf->channel <= 14) rfcsr = 0x1a; else rfcsr = 0x12; rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); if (rf->channel >= 1 && rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); else if (rf->channel >= 36 && rf->channel <= 64) @@ -2606,7 +2610,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); @@ -2620,11 +2624,11 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 13, 0x23); } - rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 51); rt2x00_set_field8(&rfcsr, RFCSR51_BITS01, 1); rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 51); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 5); rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 3); @@ -2634,7 +2638,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 3); else @@ -2645,11 +2649,11 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 57, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 57); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x1b); else @@ -2665,7 +2669,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } /* Initiate VCO calibration */ - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); } else { @@ -2721,11 +2725,11 @@ static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (info->default_power1 > POWER_BOUND) rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); else @@ -2775,7 +2779,7 @@ static void rt2800_config_channel_rf3322(struct rt2x00_dev *rt2x00dev, rt2800_freq_cal_mode1(rt2x00dev); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); @@ -2806,11 +2810,11 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (info->default_power1 > POWER_BOUND) rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); else @@ -2818,7 +2822,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); if (rt2x00_rt(rt2x00dev, RT5392)) { - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); if (info->default_power2 > POWER_BOUND) rt2x00_set_field8(&rfcsr, RFCSR50_TX, POWER_BOUND); else @@ -2827,7 +2831,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); } - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); if (rt2x00_rt(rt2x00dev, RT5392)) { rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); @@ -2911,7 +2915,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, const bool is_11b = false; const bool is_type_ep = false; - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, (rf->channel > 14 || conf_is_ht40(conf)) ? 5 : 0); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -2919,13 +2923,13 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, /* Order of values on rf_channel entry: N, K, mod, R */ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1 & 0xff); - rt2800_rfcsr_read(rt2x00dev, 9, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 9); rt2x00_set_field8(&rfcsr, RFCSR9_K, rf->rf2 & 0xf); rt2x00_set_field8(&rfcsr, RFCSR9_N, (rf->rf1 & 0x100) >> 8); rt2x00_set_field8(&rfcsr, RFCSR9_MOD, ((rf->rf3 - 8) & 0x4) >> 2); rt2800_rfcsr_write(rt2x00dev, 9, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf4 - 1); rt2x00_set_field8(&rfcsr, RFCSR11_MOD, (rf->rf3 - 8) & 0x3); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); @@ -3093,7 +3097,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, ep_reg = 0x3; } - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (info->default_power1 > power_bound) rt2x00_set_field8(&rfcsr, RFCSR49_TX, power_bound); else @@ -3102,7 +3106,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR49_EP, ep_reg); rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); if (info->default_power2 > power_bound) rt2x00_set_field8(&rfcsr, RFCSR50_TX, power_bound); else @@ -3111,7 +3115,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR50_EP, ep_reg); rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); @@ -3144,7 +3148,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2800_freq_cal_mode1(rt2x00dev); /* TODO merge with others */ - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); @@ -3186,7 +3190,7 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, /* Rdiv setting (set 0x03 if Xtal==20) * R13[1:0] */ - rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 13); rt2x00_set_field8(&rfcsr, RFCSR13_RDIV_MT7620, rt2800_clk_is_20mhz(rt2x00dev) ? 3 : 0); rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); @@ -3195,25 +3199,25 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, * R20[7:0] in rf->rf1 * R21[0] always 0 */ - rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 20); rfcsr = (rf->rf1 & 0x00ff); rt2800_rfcsr_write(rt2x00dev, 20, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); rt2x00_set_field8(&rfcsr, RFCSR21_BIT1, 0); rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); /* K setting (always 0) * R16[3:0] (RF PLL freq selection) */ - rt2800_rfcsr_read(rt2x00dev, 16, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); rt2x00_set_field8(&rfcsr, RFCSR16_RF_PLL_FREQ_SEL_MT7620, 0); rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); /* D setting (always 0) * R22[2:0] (D=15, R22[2:0]=<111>) */ - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 22); rt2x00_set_field8(&rfcsr, RFCSR22_FREQPLAN_D_MT7620, 0); rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); @@ -3222,40 +3226,40 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, * R18<7:0> in rf->rf3 * R19<1:0> in rf->rf4 */ - rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 17); rfcsr = rf->rf2; rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 18); rfcsr = rf->rf3; rt2800_rfcsr_write(rt2x00dev, 18, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 19, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 19); rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4); rt2800_rfcsr_write(rt2x00dev, 19, rfcsr); /* Default: XO=20MHz , SDM mode */ - rt2800_rfcsr_read(rt2x00dev, 16, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80); rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1); rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620, rt2x00dev->default_ant.tx_chain_num != 1); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 2); rt2x00_set_field8(&rfcsr, RFCSR2_TX2_EN_MT7620, rt2x00dev->default_ant.tx_chain_num != 1); rt2x00_set_field8(&rfcsr, RFCSR2_RX2_EN_MT7620, rt2x00dev->default_ant.rx_chain_num != 1); rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 42, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 42); rt2x00_set_field8(&rfcsr, RFCSR42_TX2_EN_MT7620, rt2x00dev->default_ant.tx_chain_num != 1); rt2800_rfcsr_write(rt2x00dev, 42, rfcsr); @@ -3283,7 +3287,7 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28); } - rt2800_rfcsr_read(rt2x00dev, 28, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 28); rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40, conf_is_ht40(conf) && (rf->channel == 11)); rt2800_rfcsr_write(rt2x00dev, 28, rfcsr); @@ -3296,36 +3300,36 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, rx_agc_fc = drv_data->rx_calibration_bw20; tx_agc_fc = drv_data->tx_calibration_bw20; } - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 6, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 7, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 6); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 6, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 7); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 7, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 58, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 59, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 58, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 58); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 58, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 59, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 59); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 59, rfcsr); @@ -3350,34 +3354,33 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, if (max_power > 0x2f) max_power = 0x2f; - rt2800_register_read(rt2x00dev, TX_ALC_CFG_0, ®); + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_0); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_0, power_level); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_1, power_level); rt2x00_set_field32(®, TX_ALC_CFG_0_LIMIT_0, max_power); rt2x00_set_field32(®, TX_ALC_CFG_0_LIMIT_1, max_power); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_INTERNAL_TX_ALC)) { /* init base power by eeprom target power */ - rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_INIT, - &target_power); + target_power = rt2800_eeprom_read(rt2x00dev, + EEPROM_TXPOWER_INIT); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_0, target_power); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_1, target_power); } rt2800_register_write(rt2x00dev, TX_ALC_CFG_0, reg); - rt2800_register_read(rt2x00dev, TX_ALC_CFG_1, ®); + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1); rt2x00_set_field32(®, TX_ALC_CFG_1_TX_TEMP_COMP, 0); rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg); /* Save MAC SYS CTRL registers */ - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &mac_sys_ctrl); + mac_sys_ctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); /* Disable Tx/Rx */ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); /* Check MAC Tx/Rx idle */ for (i = 0; i < 10000; i++) { - rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, - &mac_status); + mac_status = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); if (mac_status & 0x3) usleep_range(50, 200); else @@ -3388,7 +3391,7 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n"); if (chan->center_freq > 2457) { - rt2800_bbp_read(rt2x00dev, 30, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 30); bbp = 0x40; rt2800_bbp_write(rt2x00dev, 30, bbp); rt2800_rfcsr_write(rt2x00dev, 39, 0); @@ -3397,7 +3400,7 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, else rt2800_rfcsr_write(rt2x00dev, 42, 0x7b); } else { - rt2800_bbp_read(rt2x00dev, 30, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 30); bbp = 0x1f; rt2800_bbp_write(rt2x00dev, 30, bbp); rt2800_rfcsr_write(rt2x00dev, 39, 0x80); @@ -3418,7 +3421,7 @@ static void rt2800_bbp_write_with_rx_chain(struct rt2x00_dev *rt2x00dev, u8 chain, reg; for (chain = 0; chain < rt2x00dev->default_ant.rx_chain_num; chain++) { - rt2800_bbp_read(rt2x00dev, 27, ®); + reg = rt2800_bbp_read(rt2x00dev, 27); rt2x00_set_field8(®, BBP27_RX_CHAIN_SEL, chain); rt2800_bbp_write(rt2x00dev, 27, reg); @@ -3597,7 +3600,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_rf(rt2x00dev, RF5372) || rt2x00_rf(rt2x00dev, RF5390) || rt2x00_rf(rt2x00dev, RF5392)) { - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); if (rt2x00_rf(rt2x00dev, RF3322)) { rt2x00_set_field8(&rfcsr, RF3322_RFCSR30_TX_H20M, conf_is_ht40(conf)); @@ -3611,7 +3614,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); } @@ -3690,7 +3693,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_bbp_write(rt2x00dev, 75, 0x50); } - rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_BAND_CFG); rt2x00_set_field32(®, TX_BAND_CFG_HT40_MINUS, conf_is_ht40_minus(conf)); rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); @@ -3699,7 +3702,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rt2x00_rt(rt2x00dev, RT3572)) rt2800_rfcsr_write(rt2x00dev, 8, 0); - rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); + tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); switch (rt2x00dev->default_ant.tx_chain_num) { case 3: @@ -3765,7 +3768,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); /* Band selection */ if (rt2x00_is_usb(rt2x00dev) || @@ -3832,11 +3835,11 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_iq_calibrate(rt2x00dev, rf->channel); } - rt2800_bbp_read(rt2x00dev, 4, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800_bbp_read(rt2x00dev, 3, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&bbp, BBP3_HT40_MINUS, conf_is_ht40_minus(conf)); rt2800_bbp_write(rt2x00dev, 3, bbp); @@ -3857,16 +3860,16 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, /* * Clear channel statistic counters */ - rt2800_register_read(rt2x00dev, CH_IDLE_STA, ®); - rt2800_register_read(rt2x00dev, CH_BUSY_STA, ®); - rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); + reg = rt2800_register_read(rt2x00dev, CH_IDLE_STA); + reg = rt2800_register_read(rt2x00dev, CH_BUSY_STA); + reg = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); /* * Clear update flag */ if (rt2x00_rt(rt2x00dev, RT3352) || rt2x00_rt(rt2x00dev, RT5350)) { - rt2800_bbp_read(rt2x00dev, 49, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 49); rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0); rt2800_bbp_write(rt2x00dev, 49, bbp); } @@ -3883,7 +3886,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) /* * First check if temperature compensation is supported. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (!rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC)) return 0; @@ -3896,62 +3899,62 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 */ if (rt2x00dev->curr_band == NL80211_BAND_2GHZ) { - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1); tssi_bounds[0] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG1_MINUS4); tssi_bounds[1] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG1_MINUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2); tssi_bounds[2] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG2_MINUS2); tssi_bounds[3] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG2_MINUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3); tssi_bounds[4] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG3_REF); tssi_bounds[5] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG3_PLUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4); tssi_bounds[6] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG4_PLUS2); tssi_bounds[7] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG4_PLUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5); tssi_bounds[8] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG5_PLUS4); step = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG5_AGC_STEP); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1); tssi_bounds[0] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A1_MINUS4); tssi_bounds[1] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A1_MINUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2); tssi_bounds[2] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A2_MINUS2); tssi_bounds[3] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A2_MINUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3); tssi_bounds[4] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A3_REF); tssi_bounds[5] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A3_PLUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4); tssi_bounds[6] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A4_PLUS2); tssi_bounds[7] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A4_PLUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5); tssi_bounds[8] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A5_PLUS4); @@ -3968,7 +3971,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) /* * Read current TSSI (BBP 49). */ - rt2800_bbp_read(rt2x00dev, 49, ¤t_tssi); + current_tssi = rt2800_bbp_read(rt2x00dev, 49); /* * Compare TSSI value (BBP49) with the compensation boundaries @@ -3997,7 +4000,7 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, u8 comp_type; int comp_value = 0; - rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA); /* * HT40 compensation not required. @@ -4075,13 +4078,13 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, * .11b data rate need add additional 4dbm * when calculating eirp txpower. */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + 1); criterion = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER); if (band == NL80211_BAND_2GHZ) eirp_txpower_criterion = rt2x00_get_field16(eeprom, @@ -4150,8 +4153,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, offset += 8; /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset); /* CCK 1MBS,2MBS */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4198,8 +4201,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_0_EXT_OFDM12_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 1); /* OFDM 24MBS,36MBS */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4235,8 +4238,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_7_OFDM54_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 2, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 2); /* MCS 0,1 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4283,8 +4286,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_2_EXT_MCS6_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 3, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 3); /* MCS 7 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4331,8 +4334,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_3_EXT_MCS12_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 4, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 4); /* MCS 14 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4379,8 +4382,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_5_MCS18_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 5, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 5); /* MCS 20,21 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4416,8 +4419,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_8_MCS23_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 6, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 6); /* STBC, MCS 0,1 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4460,8 +4463,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 7, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 7); /* STBC, MCS 7 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4541,8 +4544,9 @@ static void rt2800_config_txpower_rt6352(struct rt2x00_dev *rt2x00dev, * board vendors expected when they populated the EEPROM... */ for (i = 0; i < 5; i++) { - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - i * 2, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + i * 2); data = eeprom; @@ -4558,8 +4562,9 @@ static void rt2800_config_txpower_rt6352(struct rt2x00_dev *rt2x00dev, gdata |= (t << 8); - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - (i * 2) + 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + (i * 2) + 1); t = eeprom & 0x3f; if (t == 32) @@ -4601,26 +4606,26 @@ static void rt2800_config_txpower_rt6352(struct rt2x00_dev *rt2x00dev, /* For OFDM 54MBS use value from OFDM 48MBS */ pwreg = 0; - rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_1); t = rt2x00_get_field32(reg, TX_PWR_CFG_1B_48MBS); rt2x00_set_field32(&pwreg, TX_PWR_CFG_7B_54MBS, t); /* For MCS 7 use value from MCS 6 */ - rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_2); t = rt2x00_get_field32(reg, TX_PWR_CFG_2B_MCS6_MCS7); rt2x00_set_field32(&pwreg, TX_PWR_CFG_7B_MCS7, t); rt2800_register_write(rt2x00dev, TX_PWR_CFG_7, pwreg); /* For MCS 15 use value from MCS 14 */ pwreg = 0; - rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_3); t = rt2x00_get_field32(reg, TX_PWR_CFG_3B_MCS14); rt2x00_set_field32(&pwreg, TX_PWR_CFG_8B_MCS15, t); rt2800_register_write(rt2x00dev, TX_PWR_CFG_8, pwreg); /* For STBC MCS 7 use value from STBC MCS 6 */ pwreg = 0; - rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_4); t = rt2x00_get_field32(reg, TX_PWR_CFG_4B_STBC_MCS6); rt2x00_set_field32(&pwreg, TX_PWR_CFG_9B_STBC_MCS7, t); rt2800_register_write(rt2x00dev, TX_PWR_CFG_9, pwreg); @@ -4702,7 +4707,7 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, } else { power_ctrl = 0; } - rt2800_bbp_read(rt2x00dev, 1, &r1); + r1 = rt2800_bbp_read(rt2x00dev, 1); rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl); rt2800_bbp_write(rt2x00dev, 1, r1); @@ -4713,11 +4718,12 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, if (offset > TX_PWR_CFG_4) break; - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - i, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + i); is_rate_b = i ? 0 : 1; /* @@ -4765,8 +4771,9 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - i + 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + i + 1); is_rate_b = 0; /* @@ -4853,7 +4860,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) * periodically to adjust the frequency to be precision. */ - rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); + tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); tx_pin &= TX_PIN_CFG_PA_PE_DISABLE; rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); @@ -4864,7 +4871,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF3022: case RF3320: case RF3052: - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); break; @@ -4879,7 +4886,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF5390: case RF5392: case RF5592: - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); min_sleep = 1000; @@ -4887,7 +4894,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF7620: rt2800_rfcsr_write(rt2x00dev, 5, 0x40); rt2800_rfcsr_write(rt2x00dev, 4, 0x0C); - rt2800_rfcsr_read(rt2x00dev, 4, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 4); rt2x00_set_field8(&rfcsr, RFCSR4_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 4, rfcsr); min_sleep = 2000; @@ -4901,7 +4908,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) if (min_sleep > 0) usleep_range(min_sleep, min_sleep * 2); - rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); + tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); if (rt2x00dev->rf_channel <= 14) { switch (rt2x00dev->default_ant.tx_chain_num) { case 3: @@ -4975,7 +4982,7 @@ static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTY_CFG); rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, libconf->conf->short_frame_max_tx_count); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, @@ -4994,7 +5001,7 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, libconf->conf->listen_interval - 1); @@ -5003,7 +5010,7 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); } else { - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); @@ -5046,7 +5053,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual) /* * Update FCS error count from register. */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT0); qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); } EXPORT_SYMBOL_GPL(rt2800_link_stats); @@ -5175,7 +5182,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 1600); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); @@ -5186,43 +5193,43 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_config_filter(rt2x00dev, FIF_ALLMULTI); - rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG); rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, 9); rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); if (rt2x00_rt(rt2x00dev, RT3290)) { - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); if (rt2x00_get_field32(reg, WLAN_EN) == 1) { rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 1); rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); } - rt2800_register_read(rt2x00dev, CMB_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, CMB_CTRL); if (!(rt2x00_get_field32(reg, LDO0_EN) == 1)) { rt2x00_set_field32(®, LDO0_EN, 1); rt2x00_set_field32(®, LDO_BGSEL, 3); rt2800_register_write(rt2x00dev, CMB_CTRL, reg); } - rt2800_register_read(rt2x00dev, OSC_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, OSC_CTRL); rt2x00_set_field32(®, OSC_ROSC_EN, 1); rt2x00_set_field32(®, OSC_CAL_REQ, 1); rt2x00_set_field32(®, OSC_REF_CYCLE, 0x27); rt2800_register_write(rt2x00dev, OSC_CTRL, reg); - rt2800_register_read(rt2x00dev, COEX_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, COEX_CFG0); rt2x00_set_field32(®, COEX_CFG_ANT, 0x5e); rt2800_register_write(rt2x00dev, COEX_CFG0, reg); - rt2800_register_read(rt2x00dev, COEX_CFG2, ®); + reg = rt2800_register_read(rt2x00dev, COEX_CFG2); rt2x00_set_field32(®, BT_COEX_CFG1, 0x00); rt2x00_set_field32(®, BT_COEX_CFG0, 0x17); rt2x00_set_field32(®, WL_COEX_CFG1, 0x93); rt2x00_set_field32(®, WL_COEX_CFG0, 0x7f); rt2800_register_write(rt2x00dev, COEX_CFG2, reg); - rt2800_register_read(rt2x00dev, PLL_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, PLL_CTRL); rt2x00_set_field32(®, PLL_CONTROL, 1); rt2800_register_write(rt2x00dev, PLL_CTRL, reg); } @@ -5243,8 +5250,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000002c); @@ -5279,8 +5285,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); if (rt2x00_rt_rev_lt(rt2x00dev, RT3593, REV_RT3593E)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2800_register_write(rt2x00dev, TX_SW_CFG2, @@ -5319,7 +5324,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) 0x3630363A); rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT, 0x3630363A); - rt2800_register_read(rt2x00dev, TX_ALC_CFG_1, ®); + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1); rt2x00_set_field32(®, TX_ALC_CFG_1_ROS_BUSY_EN, 0); rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg); } else { @@ -5327,7 +5332,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); } - rt2800_register_read(rt2x00dev, TX_LINK_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_LINK_CFG); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); @@ -5338,13 +5343,13 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg); - rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG); rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 32); rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MAX_LEN_CFG); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); if (rt2x00_is_usb(rt2x00dev)) { drv_data->max_psdu = 3; @@ -5360,7 +5365,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 10); rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); - rt2800_register_read(rt2x00dev, LED_CFG, ®); + reg = rt2800_register_read(rt2x00dev, LED_CFG); rt2x00_set_field32(®, LED_CFG_ON_PERIOD, 70); rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, 30); rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); @@ -5372,7 +5377,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); - rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTY_CFG); rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, 2); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, 2); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); @@ -5381,7 +5386,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTO_RSP_CFG); rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, 1); rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 1); @@ -5391,7 +5396,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, CCK_PROT_CFG); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 3); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5404,7 +5409,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 1); rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 3); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5417,7 +5422,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 1); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5430,7 +5435,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM40_PROT_CFG); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5443,7 +5448,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF20_PROT_CFG); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5456,7 +5461,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF40_PROT_CFG); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5472,7 +5477,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); @@ -5489,7 +5494,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) * The legacy driver also sets TXOP_CTRL_CFG_RESERVED_TRUN_EN to 1 * although it is reserved. */ - rt2800_register_read(rt2x00dev, TXOP_CTRL_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TXOP_CTRL_CFG); rt2x00_set_field32(®, TXOP_CTRL_CFG_TIMEOUT_TRUN_EN, 1); rt2x00_set_field32(®, TXOP_CTRL_CFG_AC_TRUN_EN, 1); rt2x00_set_field32(®, TXOP_CTRL_CFG_TXRATEGRP_TRUN_EN, 1); @@ -5505,7 +5510,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) reg = rt2x00_rt(rt2x00dev, RT5592) ? 0x00000082 : 0x00000002; rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, reg); - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTS_CFG); rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 7); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, IEEE80211_MAX_RTS_THRESHOLD); @@ -5521,7 +5526,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) * connection problems with 11g + CTS protection. Hence, use the same * defaults as the Ralink driver: 16 for both, CCK and OFDM SIFS. */ - rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, XIFS_TIME_CFG); rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, 16); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, 16); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); @@ -5551,16 +5556,16 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_clear_beacon_register(rt2x00dev, i); if (rt2x00_is_usb(rt2x00dev)) { - rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); + reg = rt2800_register_read(rt2x00dev, US_CYC_CNT); rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 30); rt2800_register_write(rt2x00dev, US_CYC_CNT, reg); } else if (rt2x00_is_pcie(rt2x00dev)) { - rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); + reg = rt2800_register_read(rt2x00dev, US_CYC_CNT); rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 125); rt2800_register_write(rt2x00dev, US_CYC_CNT, reg); } - rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, HT_FBK_CFG0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); @@ -5571,7 +5576,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg); - rt2800_register_read(rt2x00dev, HT_FBK_CFG1, ®); + reg = rt2800_register_read(rt2x00dev, HT_FBK_CFG1); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); @@ -5582,7 +5587,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg); - rt2800_register_read(rt2x00dev, LG_FBK_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LG_FBK_CFG0); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); @@ -5593,7 +5598,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg); - rt2800_register_read(rt2x00dev, LG_FBK_CFG1, ®); + reg = rt2800_register_read(rt2x00dev, LG_FBK_CFG1); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); @@ -5603,7 +5608,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) /* * Do not force the BA window size, we use the TXWI to set it */ - rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE, ®); + reg = rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE); rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE_ENABLE, 0); rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE, 0); rt2800_register_write(rt2x00dev, AMPDU_BA_WINSIZE, reg); @@ -5613,24 +5618,24 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT2, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT0); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT1); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT2); + reg = rt2800_register_read(rt2x00dev, TX_STA_CNT0); + reg = rt2800_register_read(rt2x00dev, TX_STA_CNT1); + reg = rt2800_register_read(rt2x00dev, TX_STA_CNT2); /* * Setup leadtime for pre tbtt interrupt to 6ms */ - rt2800_register_read(rt2x00dev, INT_TIMER_CFG, ®); + reg = rt2800_register_read(rt2x00dev, INT_TIMER_CFG); rt2x00_set_field32(®, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4); rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg); /* * Set up channel statistics timer */ - rt2800_register_read(rt2x00dev, CH_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, CH_TIME_CFG); rt2x00_set_field32(®, CH_TIME_CFG_EIFS_BUSY, 1); rt2x00_set_field32(®, CH_TIME_CFG_NAV_BUSY, 1); rt2x00_set_field32(®, CH_TIME_CFG_RX_BUSY, 1); @@ -5647,7 +5652,7 @@ static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) return 0; @@ -5672,7 +5677,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) msleep(1); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_bbp_read(rt2x00dev, 0, &value); + value = rt2800_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -5686,7 +5691,7 @@ static void rt2800_bbp4_mac_if_ctrl(struct rt2x00_dev *rt2x00dev) { u8 value; - rt2800_bbp_read(rt2x00dev, 4, &value); + value = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1); rt2800_bbp_write(rt2x00dev, 4, value); } @@ -5743,8 +5748,8 @@ static void rt2800_disable_unused_dac_adc(struct rt2x00_dev *rt2x00dev) u16 eeprom; u8 value; - rt2800_bbp_read(rt2x00dev, 138, &value); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + value = rt2800_bbp_read(rt2x00dev, 138); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) value |= 0x20; if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) @@ -5927,12 +5932,12 @@ static void rt2800_init_bbp_3290(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 155, 0x3b); rt2800_bbp_write(rt2x00dev, 253, 0x04); - rt2800_bbp_read(rt2x00dev, 47, &value); + value = rt2800_bbp_read(rt2x00dev, 47); rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1); rt2800_bbp_write(rt2x00dev, 47, value); /* Use 5-bit ADC for Acquisition and 8-bit ADC for data */ - rt2800_bbp_read(rt2x00dev, 3, &value); + value = rt2800_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1); rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1); rt2800_bbp_write(rt2x00dev, 3, value); @@ -6191,7 +6196,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) rt2800_disable_unused_dac_adc(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); ant = (div_mode == 3) ? 1 : 0; @@ -6200,7 +6205,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) if (rt2x00_has_cap_bt_coexist(rt2x00dev)) { u32 reg; - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR3, 0); rt2x00_set_field32(®, GPIO_CTRL_DIR6, 0); rt2x00_set_field32(®, GPIO_CTRL_VAL3, 0); @@ -6219,7 +6224,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ } - rt2800_bbp_read(rt2x00dev, 152, &value); + value = rt2800_bbp_read(rt2x00dev, 152); if (ant == 0) rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); else @@ -6237,7 +6242,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_init_bbp_early(rt2x00dev); - rt2800_bbp_read(rt2x00dev, 105, &value); + value = rt2800_bbp_read(rt2x00dev, 105); rt2x00_set_field8(&value, BBP105_MLD, rt2x00dev->default_ant.rx_chain_num == 2); rt2800_bbp_write(rt2x00dev, 105, value); @@ -6277,10 +6282,10 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_bbp4_mac_if_ctrl(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); ant = (div_mode == 3) ? 1 : 0; - rt2800_bbp_read(rt2x00dev, 152, &value); + value = rt2800_bbp_read(rt2x00dev, 152); if (ant == 0) { /* Main antenna */ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); @@ -6291,7 +6296,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 152, value); if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) { - rt2800_bbp_read(rt2x00dev, 254, &value); + value = rt2800_bbp_read(rt2x00dev, 254); rt2x00_set_field8(&value, BBP254_BIT7, 1); rt2800_bbp_write(rt2x00dev, 254, value); } @@ -6317,11 +6322,10 @@ static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev, rt2800_bbp_write(rt2x00dev, 159, value); } -static void rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, - const u8 reg, u8 *value) +static u8 rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, const u8 reg) { rt2800_bbp_write(rt2x00dev, 158, reg); - rt2800_bbp_read(rt2x00dev, 159, value); + return rt2800_bbp_read(rt2x00dev, 159); } static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) @@ -6329,7 +6333,7 @@ static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) u8 bbp; /* Apply Maximum Likelihood Detection (MLD) for 2 stream case */ - rt2800_bbp_read(rt2x00dev, 105, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 105); rt2x00_set_field8(&bbp, BBP105_MLD, rt2x00dev->default_ant.rx_chain_num == 2); rt2800_bbp_write(rt2x00dev, 105, bbp); @@ -6338,7 +6342,7 @@ static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) rt2800_bbp4_mac_if_ctrl(rt2x00dev); /* Fix I/Q swap issue */ - rt2800_bbp_read(rt2x00dev, 1, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 1); bbp |= 0x04; rt2800_bbp_write(rt2x00dev, 1, bbp); @@ -6578,8 +6582,8 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_BBP_START, i, - &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_BBP_START, i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -6593,7 +6597,7 @@ static void rt2800_led_open_drain_enable(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, OPT_14_CSR, ®); + reg = rt2800_register_read(rt2x00dev, OPT_14_CSR); rt2x00_set_field32(®, OPT_14_CSR_BIT0, 1); rt2800_register_write(rt2x00dev, OPT_14_CSR, reg); } @@ -6611,15 +6615,15 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - rt2800_bbp_read(rt2x00dev, 4, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 31); rt2x00_set_field8(&rfcsr, RFCSR31_RX_H20M, bw40); rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 22); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); @@ -6632,7 +6636,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800_bbp_read(rt2x00dev, 55, &passband); + passband = rt2800_bbp_read(rt2x00dev, 55); if (passband) break; } @@ -6646,7 +6650,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800_bbp_read(rt2x00dev, 55, &stopband); + stopband = rt2800_bbp_read(rt2x00dev, 55); if ((passband - stopband) <= filter_target) { rfcsr24++; @@ -6668,7 +6672,7 @@ static void rt2800_rf_init_calibration(struct rt2x00_dev *rt2x00dev, { u8 rfcsr; - rt2800_rfcsr_read(rt2x00dev, rf_reg, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, rf_reg); rt2x00_set_field8(&rfcsr, FIELD8(0x80), 1); rt2800_rfcsr_write(rt2x00dev, rf_reg, rfcsr); msleep(1); @@ -6702,22 +6706,22 @@ static void rt2800_rx_filter_calibration(struct rt2x00_dev *rt2x00dev) /* * Save BBP 25 & 26 values for later use in channel switching (for 3052) */ - rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25); - rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26); + drv_data->bbp25 = rt2800_bbp_read(rt2x00dev, 25); + drv_data->bbp26 = rt2800_bbp_read(rt2x00dev, 26); /* * Set back to initial state */ rt2800_bbp_write(rt2x00dev, 24, 0); - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 22); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); /* * Set BBP back to BW20 */ - rt2800_bbp_read(rt2x00dev, 4, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); rt2800_bbp_write(rt2x00dev, 4, bbp); } @@ -6728,7 +6732,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) u8 min_gain, rfcsr, bbp; u16 eeprom; - rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 17); rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0); if (rt2x00_rt(rt2x00dev, RT3070) || @@ -6749,8 +6753,8 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3090)) { /* Turn off unused DAC1 and ADC1 to reduce power consumption */ - rt2800_bbp_read(rt2x00dev, 138, &bbp); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + bbp = rt2800_bbp_read(rt2x00dev, 138); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) @@ -6759,7 +6763,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) } if (rt2x00_rt(rt2x00dev, RT3070)) { - rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 27); if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3); else @@ -6771,7 +6775,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) } else if (rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3390)) { - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); @@ -6779,15 +6783,15 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 15, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 15); rt2x00_set_field8(&rfcsr, RFCSR15_TX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 15, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 20); rt2x00_set_field8(&rfcsr, RFCSR20_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 20, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); rt2x00_set_field8(&rfcsr, RFCSR21_RX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); } @@ -6799,30 +6803,30 @@ static void rt2800_normal_mode_setup_3593(struct rt2x00_dev *rt2x00dev) u8 rfcsr; u8 tx_gain; - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 51); tx_gain = rt2x00_get_field8(drv_data->txmixer_gain_24g, RFCSR17_TXMIXER_GAIN); rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, tx_gain); rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 38); rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 38, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 39, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 39); rt2x00_set_field8(&rfcsr, RFCSR39_RX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); @@ -6835,25 +6839,25 @@ static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev) u16 eeprom; /* Turn off unused DAC1 and ADC1 to reduce power consumption */ - rt2800_bbp_read(rt2x00dev, 138, ®); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + reg = rt2800_bbp_read(rt2x00dev, 138); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(®, BBP138_RX_ADC1, 0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) rt2x00_set_field8(®, BBP138_TX_DAC1, 1); rt2800_bbp_write(rt2x00dev, 138, reg); - rt2800_rfcsr_read(rt2x00dev, 38, ®); + reg = rt2800_rfcsr_read(rt2x00dev, 38); rt2x00_set_field8(®, RFCSR38_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 38, reg); - rt2800_rfcsr_read(rt2x00dev, 39, ®); + reg = rt2800_rfcsr_read(rt2x00dev, 39); rt2x00_set_field8(®, RFCSR39_RX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 39, reg); rt2800_bbp4_mac_if_ctrl(rt2x00dev); - rt2800_rfcsr_read(rt2x00dev, 30, ®); + reg = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(®, RFCSR30_RX_VCM, 2); rt2800_rfcsr_write(rt2x00dev, 30, reg); } @@ -6926,7 +6930,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) { - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -6934,16 +6938,15 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT3090)) { rt2800_rfcsr_write(rt2x00dev, 31, 0x14); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); else @@ -6951,7 +6954,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) } rt2800_register_write(rt2x00dev, LDO_CFG0, reg); - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); rt2x00_set_field32(®, GPIO_SWITCH_5, 0); rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); } @@ -7020,7 +7023,7 @@ static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 60, 0x45); rt2800_rfcsr_write(rt2x00dev, 61, 0xc1); - rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 29); rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3); rt2800_rfcsr_write(rt2x00dev, 29, rfcsr); @@ -7166,7 +7169,7 @@ static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 30, 0x20); rt2800_rfcsr_write(rt2x00dev, 31, 0x0f); - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); rt2x00_set_field32(®, GPIO_SWITCH_5, 0); rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); @@ -7218,16 +7221,16 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 30, 0x09); rt2800_rfcsr_write(rt2x00dev, 31, 0x10); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); msleep(1); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -7242,7 +7245,7 @@ static void rt3593_post_bbp_init(struct rt2x00_dev *rt2x00dev) u8 bbp; bool txbf_enabled = false; /* FIXME */ - rt2800_bbp_read(rt2x00dev, 105, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 105); if (rt2x00dev->default_ant.rx_chain_num == 1) rt2x00_set_field8(&bbp, BBP105_MLD, 0); else @@ -7291,7 +7294,7 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) u8 rfcsr; /* Disable GPIO #4 and #7 function for LAN PE control */ - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); rt2x00_set_field32(®, GPIO_SWITCH_4, 0); rt2x00_set_field32(®, GPIO_SWITCH_7, 0); rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); @@ -7332,22 +7335,22 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) /* Initiate calibration */ /* TODO: use rt2800_rf_init_calibration ? */ - rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 2); rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); rt2800_freq_cal_mode1(rt2x00dev); - rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 18); rt2x00_set_field8(&rfcsr, RFCSR18_XO_TUNE_BYPASS, 1); rt2800_rfcsr_write(rt2x00dev, 18, rfcsr); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); usleep_range(1000, 1500); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -7356,8 +7359,8 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) drv_data->calibration_bw40 = 0x2f; /* Save BBP 25 & 26 values for later use in channel switching */ - rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25); - rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26); + drv_data->bbp25 = rt2800_bbp_read(rt2x00dev, 25); + drv_data->bbp26 = rt2800_bbp_read(rt2x00dev, 26); rt2800_led_open_drain_enable(rt2x00dev); rt2800_normal_mode_setup_3593(rt2x00dev); @@ -7651,19 +7654,19 @@ static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, { u8 bbp_val; - rt2800_bbp_read(rt2x00dev, 21, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 21); bbp_val |= 0x1; rt2800_bbp_write(rt2x00dev, 21, bbp_val); usleep_range(100, 200); if (set_bw) { - rt2800_bbp_read(rt2x00dev, 4, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp_val, BBP4_BANDWIDTH, 2 * is_ht40); rt2800_bbp_write(rt2x00dev, 4, bbp_val); usleep_range(100, 200); } - rt2800_bbp_read(rt2x00dev, 21, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 21); bbp_val &= (~0x1); rt2800_bbp_write(rt2x00dev, 21, bbp_val); usleep_range(100, 200); @@ -7680,7 +7683,7 @@ static int rt2800_rf_lp_config(struct rt2x00_dev *rt2x00dev, bool btxcal) rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x06); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 17, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17); rf_val |= 0x80; rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, rf_val); @@ -7688,11 +7691,11 @@ static int rt2800_rf_lp_config(struct rt2x00_dev *rt2x00dev, bool btxcal) rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0xC1); rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0x20); rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x02); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 3, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); rf_val &= (~0x3F); rf_val |= 0x3F; rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 4, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); rf_val &= (~0x3F); rf_val |= 0x3F; rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, rf_val); @@ -7701,11 +7704,11 @@ static int rt2800_rf_lp_config(struct rt2x00_dev *rt2x00dev, bool btxcal) rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0xF1); rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0x18); rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x02); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 3, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); rf_val &= (~0x3F); rf_val |= 0x34; rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 4, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); rf_val &= (~0x3F); rf_val |= 0x34; rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, rf_val); @@ -7725,14 +7728,14 @@ static char rt2800_lp_tx_filter_bw_cal(struct rt2x00_dev *rt2x00dev) cnt = 0; do { usleep_range(500, 2000); - rt2800_bbp_read(rt2x00dev, 159, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 159); if (bbp_val == 0x02 || cnt == 20) break; cnt++; } while (cnt < 20); - rt2800_bbp_dcoc_read(rt2x00dev, 0x39, &bbp_val); + bbp_val = rt2800_bbp_dcoc_read(rt2x00dev, 0x39); cal_val = bbp_val & 0x7F; if (cal_val >= 0x40) cal_val -= 128; @@ -7761,67 +7764,67 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, u32 MAC_RF_CONTROL0, MAC_RF_BYPASS0; /* Save MAC registers */ - rt2800_register_read(rt2x00dev, RF_CONTROL0, &MAC_RF_CONTROL0); - rt2800_register_read(rt2x00dev, RF_BYPASS0, &MAC_RF_BYPASS0); + MAC_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0); + MAC_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0); /* save BBP registers */ - rt2800_bbp_read(rt2x00dev, 23, &savebbpr23); + savebbpr23 = rt2800_bbp_read(rt2x00dev, 23); - rt2800_bbp_dcoc_read(rt2x00dev, 0, &savebbp159r0); - rt2800_bbp_dcoc_read(rt2x00dev, 2, &savebbp159r2); + savebbp159r0 = rt2800_bbp_dcoc_read(rt2x00dev, 0); + savebbp159r2 = rt2800_bbp_dcoc_read(rt2x00dev, 2); /* Save RF registers */ - rt2800_rfcsr_read_bank(rt2x00dev, 5, 0, &saverfb5r00); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 1, &saverfb5r01); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 3, &saverfb5r03); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 4, &saverfb5r04); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 5, &saverfb5r05); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &saverfb5r06); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &saverfb5r07); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 8, &saverfb5r08); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 17, &saverfb5r17); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 18, &saverfb5r18); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 19, &saverfb5r19); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 20, &saverfb5r20); - - rt2800_rfcsr_read_bank(rt2x00dev, 5, 37, &saverfb5r37); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 38, &saverfb5r38); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 39, &saverfb5r39); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 40, &saverfb5r40); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 41, &saverfb5r41); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 42, &saverfb5r42); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 43, &saverfb5r43); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 44, &saverfb5r44); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 45, &saverfb5r45); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 46, &saverfb5r46); - - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &saverfb5r58); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &saverfb5r59); - - rt2800_rfcsr_read_bank(rt2x00dev, 5, 0, &rf_val); + saverfb5r00 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); + saverfb5r01 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); + saverfb5r03 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); + saverfb5r04 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); + saverfb5r05 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 5); + saverfb5r06 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); + saverfb5r07 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); + saverfb5r08 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 8); + saverfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17); + saverfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18); + saverfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19); + saverfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20); + + saverfb5r37 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 37); + saverfb5r38 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 38); + saverfb5r39 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 39); + saverfb5r40 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 40); + saverfb5r41 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 41); + saverfb5r42 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 42); + saverfb5r43 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 43); + saverfb5r44 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 44); + saverfb5r45 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 45); + saverfb5r46 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 46); + + saverfb5r58 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); + saverfb5r59 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); + + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); rf_val |= 0x3; rt2800_rfcsr_write_bank(rt2x00dev, 5, 0, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 1, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); rf_val |= 0x1; rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, rf_val); cnt = 0; do { usleep_range(500, 2000); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 1, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); if (((rf_val & 0x1) == 0x00) || (cnt == 40)) break; cnt++; } while (cnt < 40); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 0, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); rf_val &= (~0x3); rf_val |= 0x1; rt2800_rfcsr_write_bank(rt2x00dev, 5, 0, rf_val); /* I-3 */ - rt2800_bbp_read(rt2x00dev, 23, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 23); bbp_val &= (~0x1F); bbp_val |= 0x10; rt2800_bbp_write(rt2x00dev, 23, bbp_val); @@ -7844,7 +7847,7 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, filter_target = rx_filter_target_40m; } - rt2800_rfcsr_read_bank(rt2x00dev, 5, 8, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 8); rf_val &= (~0x04); if (loop == 1) rf_val |= 0x4; @@ -7856,25 +7859,25 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, rt2800_rf_lp_config(rt2x00dev, btxcal); if (btxcal) { tx_agc_fc = 0; - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 58, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 59, rf_val); } else { rx_agc_fc = 0; - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 6, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 7, rf_val); } usleep_range(1000, 2000); - rt2800_bbp_dcoc_read(rt2x00dev, 2, &bbp_val); + bbp_val = rt2800_bbp_dcoc_read(rt2x00dev, 2); bbp_val &= (~0x6); rt2800_bbp_dcoc_write(rt2x00dev, 2, bbp_val); @@ -7882,25 +7885,25 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, cal_r32_init = rt2800_lp_tx_filter_bw_cal(rt2x00dev); - rt2800_bbp_dcoc_read(rt2x00dev, 2, &bbp_val); + bbp_val = rt2800_bbp_dcoc_read(rt2x00dev, 2); bbp_val |= 0x6; rt2800_bbp_dcoc_write(rt2x00dev, 2, bbp_val); do_cal: if (btxcal) { - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); rf_val &= (~0x7F); rf_val |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 58, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); rf_val &= (~0x7F); rf_val |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 59, rf_val); } else { - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); rf_val &= (~0x7F); rf_val |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 6, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); rf_val &= (~0x7F); rf_val |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 7, rf_val); @@ -7980,7 +7983,7 @@ do_cal: rt2800_bbp_dcoc_write(rt2x00dev, 0, savebbp159r0); rt2800_bbp_dcoc_write(rt2x00dev, 2, savebbp159r2); - rt2800_bbp_read(rt2x00dev, 4, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp_val, BBP4_BANDWIDTH, 2 * test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)); rt2800_bbp_write(rt2x00dev, 4, bbp_val); @@ -8355,20 +8358,20 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); udelay(50); - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); @@ -8376,15 +8379,15 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize LED control */ - rt2800_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF); rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff, word & 0xff, (word >> 8) & 0xff); - rt2800_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF); rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff, word & 0xff, (word >> 8) & 0xff); - rt2800_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY); rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff, word & 0xff, (word >> 8) & 0xff); @@ -8401,7 +8404,7 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) /* Wait for DMA, ignore error */ rt2800_wait_wpdma_ready(rt2x00dev); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 0); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); @@ -8418,7 +8421,7 @@ int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) else efuse_ctrl_reg = EFUSE_CTRL; - rt2800_register_read(rt2x00dev, efuse_ctrl_reg, ®); + reg = rt2800_register_read(rt2x00dev, efuse_ctrl_reg); return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT); } EXPORT_SYMBOL_GPL(rt2800_efuse_detect); @@ -8447,7 +8450,7 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) } mutex_lock(&rt2x00dev->csr_mutex); - rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg); rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); @@ -8456,14 +8459,14 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) /* Wait until the EEPROM has been loaded */ rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, ®); /* Apparently the data is read from end to start */ - rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data3_reg); /* The returned value is in CPU order, but eeprom is le */ *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data2_reg); *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data1_reg); *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data0_reg); *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg); mutex_unlock(&rt2x00dev->csr_mutex); @@ -8487,7 +8490,7 @@ static u8 rt2800_get_txmixer_gain_24g(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3593)) return 0; - rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG); if ((word & 0x00ff) != 0x00ff) return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL); @@ -8501,7 +8504,7 @@ static u8 rt2800_get_txmixer_gain_5g(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3593)) return 0; - rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A); if ((word & 0x00ff) != 0x00ff) return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL); @@ -8529,7 +8532,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2800_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2); rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1); @@ -8546,7 +8549,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); } - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0); rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0); @@ -8567,7 +8570,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ); if ((word & 0x00ff) == 0x00ff) { rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); rt2800_eeprom_write(rt2x00dev, EEPROM_FREQ, word); @@ -8589,10 +8592,10 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) * lna0 as correct value. Note that EEPROM_LNA * is never validated. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LNA); default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) @@ -8601,7 +8604,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) drv_data->txmixer_gain_24g = rt2800_get_txmixer_gain_24g(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); if (!rt2x00_rt(rt2x00dev, RT3593)) { @@ -8614,14 +8617,14 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) drv_data->txmixer_gain_5g = rt2800_get_txmixer_gain_5g(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); if (!rt2x00_rt(rt2x00dev, RT3593)) { @@ -8633,7 +8636,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2); if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0x00 || rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0xff) rt2x00_set_field16(&word, EEPROM_EXT_LNA2_A1, @@ -8657,7 +8660,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); /* * Identify RF chipset by EEPROM value @@ -8668,7 +8671,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392) || rt2x00_rt(rt2x00dev, RT6352)) - rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); + rf = rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID); else if (rt2x00_rt(rt2x00dev, RT3352)) rf = RF3322; else if (rt2x00_rt(rt2x00dev, RT5350)) @@ -8717,7 +8720,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00dev->default_ant.rx_chain_num = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3090) || @@ -8771,7 +8774,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read frequency offset and RF programming sequence. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ); rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); /* @@ -8788,7 +8791,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Check if support EIRP tx power limit feature. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER); if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) < EIRP_MAX_TX_POWER_LIMIT) @@ -8797,7 +8800,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if device uses internal or external PA */ - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_rt(rt2x00dev, RT3352)) { if (rt2x00_get_field16(eeprom, @@ -9239,7 +9242,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) break; case RF5592: - rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX, ®); + reg = rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX); if (rt2x00_get_field32(reg, MAC_DEBUG_INDEX_XTAL)) { spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal40); spec->channels = rf_vals_5592_xtal40; @@ -9378,9 +9381,9 @@ static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev) u32 rev; if (rt2x00_rt(rt2x00dev, RT3290)) - rt2800_register_read(rt2x00dev, MAC_CSR0_3290, ®); + reg = rt2800_register_read(rt2x00dev, MAC_CSR0_3290); else - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2800_register_read(rt2x00dev, MAC_CSR0); rt = rt2x00_get_field32(reg, MAC_CSR0_CHIPSET); rev = rt2x00_get_field32(reg, MAC_CSR0_REVISION); @@ -9440,7 +9443,7 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR2, 1); rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); @@ -9515,31 +9518,31 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) u32 reg; bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTS_CFG); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, CCK_PROT_CFG); rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM40_PROT_CFG); rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF20_PROT_CFG); rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF40_PROT_CFG); rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); @@ -9582,7 +9585,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, queue->txop); rt2800_register_write(rt2x00dev, offset, reg); @@ -9590,22 +9593,22 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG); rt2x00_set_field32(®, field, queue->aifs); rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); - rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG); rt2x00_set_field32(®, field, queue->cw_min); rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); - rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG); rt2x00_set_field32(®, field, queue->cw_max); rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); /* Update EDCA registers */ offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); @@ -9622,9 +9625,9 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u64 tsf; u32 reg; - rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + reg = rt2800_register_read(rt2x00dev, TSF_TIMER_DW1); tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; - rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + reg = rt2800_register_read(rt2x00dev, TSF_TIMER_DW0); tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); return tsf; @@ -9691,9 +9694,9 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx, survey->channel = conf->chandef.chan; - rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle); - rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy); - rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext); + idle = rt2800_register_read(rt2x00dev, CH_IDLE_STA); + busy = rt2800_register_read(rt2x00dev, CH_BUSY_STA); + busy_ext = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); if (idle || busy) { survey->filled = SURVEY_INFO_TIME | diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index f357531d9488..275e3969abdd 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -49,10 +49,10 @@ struct rt2800_drv_data { }; struct rt2800_ops { - void (*register_read)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value); - void (*register_read_lock)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value); + u32 (*register_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset); + u32 (*register_read_lock)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset); void (*register_write)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value); void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, @@ -78,22 +78,20 @@ struct rt2800_ops { __le32 *(*drv_get_txwi)(struct queue_entry *entry); }; -static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - rt2800ops->register_read(rt2x00dev, offset, value); + return rt2800ops->register_read(rt2x00dev, offset); } -static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static inline u32 rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - rt2800ops->register_read_lock(rt2x00dev, offset, value); + return rt2800ops->register_read_lock(rt2x00dev, offset); } static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index 3ab3b5323897..ee5276e233fa 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -109,7 +109,7 @@ void rt2800mmio_fill_rxdone(struct queue_entry *entry, __le32 *rxd = entry_priv->desc; u32 word; - rt2x00_desc_read(rxd, 3, &word); + word = rt2x00_desc_read(rxd, 3); if (rt2x00_get_field32(word, RXD_W3_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -175,7 +175,7 @@ static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status) wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID); txwi = rt2800_drv_get_txwi(entry); - rt2x00_desc_read(txwi, 1, &word); + word = rt2x00_desc_read(txwi, 1); tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); return (tx_wcid == wcid); @@ -331,7 +331,7 @@ static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev, * access needs locking. */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); rt2x00_set_field32(®, irq_field, 1); rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irq(&rt2x00dev->irqmask_lock); @@ -376,12 +376,12 @@ void rt2800mmio_tbtt_tasklet(unsigned long data) * interval every 64 beacons by 64us to mitigate this effect. */ if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 2)) { - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, (rt2x00dev->beacon_int * 16) - 1); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); } else if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 1)) { - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, (rt2x00dev->beacon_int * 16)); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -439,7 +439,7 @@ static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) * need to lock the kfifo. */ for (i = 0; i < rt2x00dev->tx->limit; i++) { - rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status); + status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO); if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) break; @@ -460,7 +460,7 @@ irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) u32 reg, mask; /* Read status and ACK all interrupts */ - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); if (!reg) @@ -501,7 +501,7 @@ irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) * the tasklet will reenable the appropriate interrupts. */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); reg &= mask; rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock(&rt2x00dev->irqmask_lock); @@ -521,7 +521,7 @@ void rt2800mmio_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); } @@ -560,18 +560,18 @@ void rt2800mmio_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 1); rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg); break; @@ -613,18 +613,18 @@ void rt2800mmio_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 0); rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg); @@ -696,11 +696,11 @@ bool rt2800mmio_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); return (!rt2x00_get_field32(word, RXD_W1_DMA_DONE)); } else { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); return (!rt2x00_get_field32(word, TXD_W1_DMA_DONE)); } @@ -715,11 +715,11 @@ void rt2800mmio_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_SDP0, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 0, word); - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0); rt2x00_desc_write(entry_priv->desc, 1, word); @@ -730,7 +730,7 @@ void rt2800mmio_clear_entry(struct queue_entry *entry) rt2x00mmio_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); } else { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1); rt2x00_desc_write(entry_priv->desc, 1, word); } @@ -810,7 +810,7 @@ int rt2800mmio_init_registers(struct rt2x00_dev *rt2x00dev) /* * Reset DMA indexes */ - rt2x00mmio_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + reg = rt2x00mmio_register_read(rt2x00dev, WPDMA_RST_IDX); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); @@ -831,7 +831,7 @@ int rt2800mmio_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392) || rt2x00_rt(rt2x00dev, RT5592))) { - rt2x00mmio_register_read(rt2x00dev, AUX_CTRL, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AUX_CTRL); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); rt2x00mmio_register_write(rt2x00dev, AUX_CTRL, reg); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 0af22573a2eb..5cf655ff1430 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -69,7 +69,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) return; for (i = 0; i < 200; i++) { - rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); + reg = rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID); if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || @@ -92,7 +92,7 @@ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); @@ -122,7 +122,7 @@ static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom.data = rt2x00dev; eeprom.register_read = rt2800pci_eepromregister_read; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index f11e3f532a84..685b8e0cd67d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -61,12 +61,12 @@ static void rt2800usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); @@ -84,12 +84,12 @@ static void rt2800usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); @@ -333,7 +333,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + reg = rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL); rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); reg = 0; @@ -456,7 +456,7 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry, /* * Initialize TXINFO descriptor */ - rt2x00_desc_read(txi, 0, &word); + word = rt2x00_desc_read(txi, 0); /* * The size of TXINFO_W0_USB_DMA_TX_PKT_LEN is @@ -527,7 +527,7 @@ static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) */ txwi = rt2800usb_get_txwi(entry); - rt2x00_desc_read(txwi, 1, &word); + word = rt2x00_desc_read(txwi, 1); tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); @@ -652,7 +652,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad | * |<------------ rx_pkt_len -------------->| */ - rt2x00_desc_read(rxi, 0, &word); + word = rt2x00_desc_read(rxi, 0); rx_pkt_len = rt2x00_get_field32(word, RXINFO_W0_USB_DMA_RX_PKT_LEN); /* @@ -676,7 +676,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, /* * It is now safe to read the descriptor on all architectures. */ - rt2x00_desc_read(rxd, 0, &word); + word = rt2x00_desc_read(rxd, 0); if (rt2x00_get_field32(word, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1156,6 +1156,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x2001, 0x3c17) }, /* Panasonic */ { USB_DEVICE(0x083a, 0xb511) }, + /* Accton/Arcadyan/Epson */ + { USB_DEVICE(0x083a, 0xb512) }, /* Philips */ { USB_DEVICE(0x0471, 0x20dd) }, /* Ralink */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 1bc353eafe37..1f38c338ca7a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1049,11 +1049,11 @@ struct rt2x00_bar_list_entry { * Generic RF access. * The RF is being accessed by word index. */ -static inline void rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) +static inline u32 rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { BUG_ON(word < 1 || word > rt2x00dev->ops->rf_size / sizeof(u32)); - *data = rt2x00dev->rf[word - 1]; + return rt2x00dev->rf[word - 1]; } static inline void rt2x00_rf_write(struct rt2x00_dev *rt2x00dev, @@ -1072,10 +1072,10 @@ static inline void *rt2x00_eeprom_addr(struct rt2x00_dev *rt2x00dev, return (void *)&rt2x00dev->eeprom[word]; } -static inline void rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u16 *data) +static inline u16 rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { - *data = le16_to_cpu(rt2x00dev->eeprom[word]); + return le16_to_cpu(rt2x00dev->eeprom[word]); } static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index 964aefdc11f0..51520a0e2138 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -188,7 +188,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, return; } - dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr)); + dump_hdr = skb_put(skbcopy, sizeof(*dump_hdr)); dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION); dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr)); dump_hdr->desc_length = cpu_to_le32(skbdesc->desc_len); @@ -203,9 +203,8 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec); if (!(skbdesc->flags & SKBDESC_DESC_IN_SKB)) - memcpy(skb_put(skbcopy, skbdesc->desc_len), skbdesc->desc, - skbdesc->desc_len); - memcpy(skb_put(skbcopy, skb->len), skb->data, skb->len); + skb_put_data(skbcopy, skbdesc->desc, skbdesc->desc_len); + skb_put_data(skbcopy, skb->data, skb->len); skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy); wake_up_interruptible(&intf->frame_dump_waitqueue); @@ -460,7 +459,7 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \ if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ index *= debug->__name.word_size; \ \ - debug->__name.read(intf->rt2x00dev, index, &value); \ + value = debug->__name.read(intf->rt2x00dev, index); \ \ size = sprintf(line, __format, value); \ \ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h index e65712c235bd..a357a0727a0b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h @@ -38,8 +38,8 @@ enum rt2x00debugfs_entry_flags { #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ struct reg##__name { \ - void (*read)(struct rt2x00_dev *rt2x00dev, \ - const unsigned int word, __type *data); \ + __type (*read)(struct rt2x00_dev *rt2x00dev, \ + const unsigned int word); \ void (*write)(struct rt2x00_dev *rt2x00dev, \ const unsigned int word, __type data); \ \ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c index da38d254c26f..528cb0401df1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c @@ -43,7 +43,7 @@ int rt2x00mmio_regbusy_read(struct rt2x00_dev *rt2x00dev, return 0; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, offset, reg); + *reg = rt2x00mmio_register_read(rt2x00dev, offset); if (!rt2x00_get_field32(*reg, field)) return 1; udelay(REGISTER_BUSY_DELAY); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h index 701c3127efb9..184a4148b2f8 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h @@ -29,11 +29,10 @@ /* * Register access. */ -static inline void rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static inline u32 rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { - *value = readl(rt2x00dev->csr.base + offset); + return readl(rt2x00dev->csr.base + offset); } static inline void rt2x00mmio_register_multiread(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h index 6055f36211b9..a15bae29917b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h @@ -642,11 +642,10 @@ static inline int rt2x00queue_dma_timeout(struct queue_entry *entry) * _rt2x00_desc_read - Read a word from the hardware descriptor. * @desc: Base descriptor address * @word: Word index from where the descriptor should be read. - * @value: Address where the descriptor value should be written into. */ -static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value) +static inline __le32 _rt2x00_desc_read(__le32 *desc, const u8 word) { - *value = desc[word]; + return desc[word]; } /** @@ -654,13 +653,10 @@ static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value) * function will take care of the byte ordering. * @desc: Base descriptor address * @word: Word index from where the descriptor should be read. - * @value: Address where the descriptor value should be written into. */ -static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) +static inline u32 rt2x00_desc_read(__le32 *desc, const u8 word) { - __le32 tmp; - _rt2x00_desc_read(desc, word, &tmp); - *value = le32_to_cpu(tmp); + return le32_to_cpu(_rt2x00_desc_read(desc, word)); } /** diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c index c696f0ad6a68..e2f4f5778267 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c @@ -145,7 +145,7 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, return -ENODEV; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2x00usb_register_read_lock(rt2x00dev, offset, reg); + *reg = rt2x00usb_register_read_lock(rt2x00dev, offset); if (!rt2x00_get_field32(*reg, field)) return 1; udelay(REGISTER_BUSY_DELAY); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h index 569363da00a2..ff94c6944cfc 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h @@ -190,40 +190,36 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, * rt2x00usb_register_read - Read 32bit register word * @rt2x00dev: Device pointer, see &struct rt2x00_dev. * @offset: Register offset - * @value: Pointer to where register contents should be stored * * This function is a simple wrapper for 32bit register access * through rt2x00usb_vendor_request_buff(). */ -static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static inline u32 rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le32 reg = 0; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg)); - *value = le32_to_cpu(reg); + return le32_to_cpu(reg); } /** * rt2x00usb_register_read_lock - Read 32bit register word * @rt2x00dev: Device pointer, see &struct rt2x00_dev. * @offset: Register offset - * @value: Pointer to where register contents should be stored * * This function is a simple wrapper for 32bit register access * through rt2x00usb_vendor_req_buff_lock(). */ -static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static inline u32 rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le32 reg = 0; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); + return le32_to_cpu(reg); } /** diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index 973d418b8113..234310200759 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -86,10 +86,11 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -112,9 +113,11 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -161,7 +164,7 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR); rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, reg); @@ -176,7 +179,7 @@ static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); @@ -240,7 +243,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); return rt2x00_get_field32(reg, MAC_CSR13_VAL5); } @@ -291,7 +294,7 @@ static int rt61pci_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14); rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); rt2x00mmio_register_write(led->rt2x00dev, MAC_CSR14, reg); @@ -336,7 +339,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = (0xf << crypto->bssidx); - rt2x00mmio_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR0); reg &= mask; if (reg && reg == mask) @@ -369,14 +372,14 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, field.bit_offset = (3 * key->hw_key_idx); field.bit_mask = 0x7 << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR1); rt2x00_set_field32(®, field, crypto->cipher); rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, reg); } else { field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_mask = 0x7 << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR5); rt2x00_set_field32(®, field, crypto->cipher); rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, reg); } @@ -401,7 +404,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = 1 << key->hw_key_idx; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR0); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -430,10 +433,10 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * When both registers are full, we drop the key. * Otherwise, we use the first invalid entry. */ - rt2x00mmio_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); if (reg && reg == ~0) { key->hw_key_idx = 32; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); if (reg && reg == ~0) return -ENOSPC; } @@ -467,7 +470,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * Without this, received frames will not be decrypted * by the hardware. */ - rt2x00mmio_register_read(rt2x00dev, SEC_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR4); reg |= (1 << crypto->bssidx); rt2x00mmio_register_write(rt2x00dev, SEC_CSR4, reg); @@ -492,7 +495,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, if (key->hw_key_idx < 32) { mask = 1 << key->hw_key_idx; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -501,7 +504,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, } else { mask = 1 << (key->hw_key_idx - 32); - rt2x00mmio_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -523,7 +526,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, @@ -555,7 +558,7 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -586,13 +589,13 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); @@ -604,18 +607,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, erp->basic_rates); if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); } if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR8); rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); @@ -630,9 +633,9 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt61pci_bbp_read(rt2x00dev, 4, &r4); - rt61pci_bbp_read(rt2x00dev, 77, &r77); + r3 = rt61pci_bbp_read(rt2x00dev, 3); + r4 = rt61pci_bbp_read(rt2x00dev, 4); + r77 = rt61pci_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325)); @@ -676,9 +679,9 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt61pci_bbp_read(rt2x00dev, 4, &r4); - rt61pci_bbp_read(rt2x00dev, 77, &r77); + r3 = rt61pci_bbp_read(rt2x00dev, 3); + r4 = rt61pci_bbp_read(rt2x00dev, 4); + r77 = rt61pci_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, @@ -712,7 +715,7 @@ static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); rt2x00_set_field32(®, MAC_CSR13_DIR4, 0); rt2x00_set_field32(®, MAC_CSR13_VAL4, p1); @@ -730,9 +733,9 @@ static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt61pci_bbp_read(rt2x00dev, 4, &r4); - rt61pci_bbp_read(rt2x00dev, 77, &r77); + r3 = rt61pci_bbp_read(rt2x00dev, 3); + r4 = rt61pci_bbp_read(rt2x00dev, 4); + r77 = rt61pci_bbp_read(rt2x00dev, 77); /* * Configure the RX antenna. @@ -819,7 +822,7 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); - rt2x00mmio_register_read(rt2x00dev, PHY_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PHY_CSR0); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, rt2x00dev->curr_band == NL80211_BAND_2GHZ); @@ -850,13 +853,13 @@ static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) lna_gain += 14; - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } else { if (rt2x00_has_cap_external_lna_a(rt2x00dev)) lna_gain += 14; - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); } @@ -875,7 +878,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); - rt61pci_bbp_read(rt2x00dev, 3, &r3); + r3 = rt61pci_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); rt61pci_bbp_write(rt2x00dev, 3, r3); @@ -913,10 +916,10 @@ static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, { struct rf_channel rf; - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rf.rf1 = rt2x00_rf_read(rt2x00dev, 1); + rf.rf2 = rt2x00_rf_read(rt2x00dev, 2); + rf.rf3 = rt2x00_rf_read(rt2x00dev, 3); + rf.rf4 = rt2x00_rf_read(rt2x00dev, 4); rt61pci_config_channel(rt2x00dev, &rf, txpower); } @@ -926,7 +929,7 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_STEP, 0); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0); @@ -946,7 +949,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, @@ -967,7 +970,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, rt61pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0); } else { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 0); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0); rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); @@ -1013,13 +1016,13 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00mmio_register_read(rt2x00dev, STA_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2x00mmio_register_read(rt2x00dev, STA_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } @@ -1138,12 +1141,12 @@ static void rt61pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); @@ -1161,22 +1164,22 @@ static void rt61pci_kick_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BE: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BK: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; @@ -1192,32 +1195,32 @@ static void rt61pci_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BE: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BK: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_RX: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); @@ -1299,7 +1302,7 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for stable hardware. */ for (i = 0; i < 100; i++) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); if (reg) break; msleep(1); @@ -1338,7 +1341,7 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); for (i = 0; i < 100; i++) { - rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR); if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY)) break; msleep(1); @@ -1362,12 +1365,12 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); @@ -1383,11 +1386,11 @@ static bool rt61pci_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || rt2x00_get_field32(word, TXD_W0_VALID)); @@ -1401,16 +1404,16 @@ static void rt61pci_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 5, &word); + word = rt2x00_desc_read(entry_priv->desc, 5); rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 5, word); - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_desc_write(entry_priv->desc, 0, word); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_desc_write(entry_priv->desc, 0, word); @@ -1425,7 +1428,7 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) /* * Initialize registers. */ - rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0); rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE, rt2x00dev->tx[0].limit); rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE, @@ -1436,36 +1439,36 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00dev->tx[3].limit); rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR0, reg); - rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1); rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE, rt2x00dev->tx[0].desc_size / 4); rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR1, reg); entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR); rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC0_BASE_CSR, reg); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR); rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC1_BASE_CSR, reg); entry_priv = rt2x00dev->tx[2].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR); rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC2_BASE_CSR, reg); entry_priv = rt2x00dev->tx[3].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR); rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC3_BASE_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR); rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit); rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE, rt2x00dev->rx->desc_size / 4); @@ -1473,26 +1476,26 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, RX_RING_CSR, reg); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR); rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, RX_BASE_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC0, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2); rt2x00mmio_register_write(rt2x00dev, TX_DMA_DST_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1); rt2x00mmio_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); rt2x00_set_field32(®, RX_CNTL_CSR_LOAD_RXD, 1); rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); @@ -1503,13 +1506,13 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ @@ -1523,7 +1526,7 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * CCK TXD BBP registers */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); @@ -1537,7 +1540,7 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * OFDM TXD BBP registers */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); @@ -1546,21 +1549,21 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR3, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR7, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR8, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); @@ -1573,7 +1576,7 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, MAC_CSR6, 0x00000fff); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); @@ -1619,24 +1622,24 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00mmio_register_read(rt2x00dev, STA_CSR0, ®); - rt2x00mmio_register_read(rt2x00dev, STA_CSR1, ®); - rt2x00mmio_register_read(rt2x00dev, STA_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR2); /* * Reset MAC and BBP registers. */ - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); @@ -1649,7 +1652,7 @@ static int rt61pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt61pci_bbp_read(rt2x00dev, 0, &value); + value = rt61pci_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -1695,7 +1698,7 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) rt61pci_bbp_write(rt2x00dev, 107, 0x04); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1722,10 +1725,10 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); } @@ -1735,7 +1738,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, */ spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); rt2x00_set_field32(®, INT_MASK_CSR_BEACON_DONE, mask); @@ -1743,7 +1746,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, mask); rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, mask); rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, mask); @@ -1783,7 +1786,7 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1); rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); @@ -1806,7 +1809,7 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) put_to_sleep = (state != STATE_AWAKE); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg); @@ -1817,7 +1820,7 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR12, ®2); + reg2 = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; @@ -1876,7 +1879,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); @@ -1887,7 +1890,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, @@ -1901,7 +1904,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } - rt2x00_desc_read(txd, 5, &word); + word = rt2x00_desc_read(txd, 5); rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); rt2x00_set_field32(&word, TXD_W5_TX_POWER, @@ -1910,12 +1913,12 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 5, word); if (entry->queue->qid != QID_BEACON) { - rt2x00_desc_read(txd, 6, &word); + word = rt2x00_desc_read(txd, 6); rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(txd, 6, word); - rt2x00_desc_read(txd, 11, &word); + word = rt2x00_desc_read(txd, 11); rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, txdesc->length); rt2x00_desc_write(txd, 11, word); @@ -1926,7 +1929,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, * the device, whereby the device may take hold of the TXD before we * finished updating it. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1975,7 +1978,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); orig_reg = reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2036,7 +2039,7 @@ static void rt61pci_clear_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &orig_reg); + orig_reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); reg = orig_reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2092,8 +2095,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, u32 word0; u32 word1; - rt2x00_desc_read(entry_priv->desc, 0, &word0); - rt2x00_desc_read(entry_priv->desc, 1, &word1); + word0 = rt2x00_desc_read(entry_priv->desc, 0); + word1 = rt2x00_desc_read(entry_priv->desc, 1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -2102,11 +2105,11 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]); - _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]); + rxdesc->iv[0] = _rt2x00_desc_read(entry_priv->desc, 2); + rxdesc->iv[1] = _rt2x00_desc_read(entry_priv->desc, 3); rxdesc->dev_flags |= RXDONE_CRYPTO_IV; - _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv); + rxdesc->icv = _rt2x00_desc_read(entry_priv->desc, 4); rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* @@ -2172,7 +2175,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) * tx ring size for now. */ for (i = 0; i < rt2x00dev->tx->limit; i++) { - rt2x00mmio_register_read(rt2x00dev, STA_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR4); if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) break; @@ -2195,7 +2198,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) entry = &queue->entries[index]; entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) @@ -2258,7 +2261,7 @@ static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); @@ -2276,7 +2279,7 @@ static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); @@ -2328,10 +2331,10 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) * Get the interrupt sources & saved to local variable. * Write register value back to clear pending interrupts. */ - rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu); + reg_mcu = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); if (!reg && !reg_mcu) @@ -2369,11 +2372,11 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); reg |= mask; rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); reg |= mask_mcu; rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); @@ -2393,7 +2396,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) u8 *mac; s8 value; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom.data = rt2x00dev; eeprom.register_read = rt61pci_eepromregister_read; @@ -2414,7 +2417,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -2429,7 +2432,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0); rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0); @@ -2442,7 +2445,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, LED_MODE_DEFAULT); @@ -2450,7 +2453,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); @@ -2458,7 +2461,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); @@ -2474,7 +2477,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); @@ -2502,13 +2505,13 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); @@ -2549,7 +2552,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read frequency offset and RF programming sequence. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags); @@ -2558,7 +2561,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read external LNA informations. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); @@ -2589,7 +2592,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * switch to default led mode. */ #ifdef CONFIG_RT2X00_LIB_LEDS - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); rt61pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); @@ -2850,7 +2853,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); rt2x00_set_field32(®, MAC_CSR13_DIR5, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg); @@ -2922,7 +2925,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, offset, ®); + reg = rt2x00mmio_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, queue->txop); rt2x00mmio_register_write(rt2x00dev, offset, reg); @@ -2930,15 +2933,15 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR); rt2x00_set_field32(®, field, queue->aifs); rt2x00mmio_register_write(rt2x00dev, AIFSN_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR); rt2x00_set_field32(®, field, queue->cw_min); rt2x00mmio_register_write(rt2x00dev, CWMIN_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR); rt2x00_set_field32(®, field, queue->cw_max); rt2x00mmio_register_write(rt2x00dev, CWMAX_CSR, reg); @@ -2951,9 +2954,9 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u64 tsf; u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13); tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); return tsf; diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index bb8d307a789f..fd913222abd1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -84,10 +84,11 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -110,9 +111,11 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, @@ -185,7 +188,7 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR13); return rt2x00_get_field32(reg, MAC_CSR13_VAL7); } @@ -238,7 +241,7 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, ®); + reg = rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14); rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg); @@ -283,7 +286,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = (0xf << crypto->bssidx); - rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR0); reg &= mask; if (reg && reg == mask) @@ -316,14 +319,14 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, field.bit_offset = (3 * key->hw_key_idx); field.bit_mask = 0x7 << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, SEC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR1); rt2x00_set_field32(®, field, crypto->cipher); rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg); } else { field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_mask = 0x7 << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, SEC_CSR5, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR5); rt2x00_set_field32(®, field, crypto->cipher); rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg); } @@ -348,7 +351,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = 1 << key->hw_key_idx; - rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR0); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -377,10 +380,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * When both registers are full, we drop the key, * otherwise we use the first invalid entry. */ - rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR2); if (reg && reg == ~0) { key->hw_key_idx = 32; - rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR3); if (reg && reg == ~0) return -ENOSPC; } @@ -417,7 +420,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * without this received frames will not be decrypted * by the hardware. */ - rt2x00usb_register_read(rt2x00dev, SEC_CSR4, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR4); reg |= (1 << crypto->bssidx); rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg); @@ -442,7 +445,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, if (key->hw_key_idx < 32) { mask = 1 << key->hw_key_idx; - rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR2); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -451,7 +454,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, } else { mask = 1 << (key->hw_key_idx - 32); - rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR3); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -473,7 +476,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, @@ -505,7 +508,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -535,13 +538,13 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); @@ -553,18 +556,18 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, erp->basic_rates); if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); - rt2x00usb_register_read(rt2x00dev, MAC_CSR8, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR8); rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); @@ -580,9 +583,9 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, u8 r77; u8 temp; - rt73usb_bbp_read(rt2x00dev, 3, &r3); - rt73usb_bbp_read(rt2x00dev, 4, &r4); - rt73usb_bbp_read(rt2x00dev, 77, &r77); + r3 = rt73usb_bbp_read(rt2x00dev, 3); + r4 = rt73usb_bbp_read(rt2x00dev, 4); + r77 = rt73usb_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); @@ -627,9 +630,9 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt73usb_bbp_read(rt2x00dev, 3, &r3); - rt73usb_bbp_read(rt2x00dev, 4, &r4); - rt73usb_bbp_read(rt2x00dev, 77, &r77); + r3 = rt73usb_bbp_read(rt2x00dev, 3); + r4 = rt73usb_bbp_read(rt2x00dev, 4); + r77 = rt73usb_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, @@ -715,7 +718,7 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); - rt2x00usb_register_read(rt2x00dev, PHY_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, PHY_CSR0); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, (rt2x00dev->curr_band == NL80211_BAND_2GHZ)); @@ -740,10 +743,10 @@ static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) lna_gain += 14; - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); } @@ -762,7 +765,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); - rt73usb_bbp_read(rt2x00dev, 3, &r3); + r3 = rt73usb_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); rt73usb_bbp_write(rt2x00dev, 3, r3); @@ -796,10 +799,10 @@ static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, { struct rf_channel rf; - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rf.rf1 = rt2x00_rf_read(rt2x00dev, 1); + rf.rf2 = rt2x00_rf_read(rt2x00dev, 2); + rf.rf3 = rt2x00_rf_read(rt2x00dev, 3); + rf.rf4 = rt2x00_rf_read(rt2x00dev, 4); rt73usb_config_channel(rt2x00dev, &rf, txpower); } @@ -809,7 +812,7 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_STEP, 0); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0); @@ -829,7 +832,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, @@ -846,7 +849,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_SLEEP, REGISTER_TIMEOUT); } else { - rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 0); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0); rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); @@ -888,13 +891,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR0); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR1); qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } @@ -1025,12 +1028,12 @@ static void rt73usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); @@ -1048,12 +1051,12 @@ static void rt73usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); @@ -1112,7 +1115,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for stable hardware. */ for (i = 0; i < 100; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR0); if (reg) break; msleep(1); @@ -1150,13 +1153,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ @@ -1170,7 +1173,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) /* * CCK TXD BBP registers */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); @@ -1184,7 +1187,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) /* * OFDM TXD BBP registers */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR3); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); @@ -1193,21 +1196,21 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR7); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR8); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); @@ -1218,7 +1221,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); - rt2x00usb_register_read(rt2x00dev, MAC_CSR6, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR6); rt2x00_set_field32(®, MAC_CSR6_MAX_FRAME_UNIT, 0xfff); rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg); @@ -1246,7 +1249,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -1266,24 +1269,24 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); - rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); - rt2x00usb_register_read(rt2x00dev, STA_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR0); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR1); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR2); /* * Reset MAC and BBP registers. */ - rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); @@ -1296,7 +1299,7 @@ static int rt73usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt73usb_bbp_read(rt2x00dev, 0, &value); + value = rt73usb_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -1343,7 +1346,7 @@ static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev) rt73usb_bbp_write(rt2x00dev, 107, 0x04); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1390,7 +1393,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) put_to_sleep = (state != STATE_AWAKE); - rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR12); rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); @@ -1401,7 +1404,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®2); + reg2 = rt2x00usb_register_read(rt2x00dev, MAC_CSR12); state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; @@ -1459,7 +1462,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_BURST, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_VALID, 1); @@ -1485,7 +1488,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); rt2x00_desc_write(txd, 0, word); - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); @@ -1495,7 +1498,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, @@ -1509,7 +1512,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } - rt2x00_desc_read(txd, 5, &word); + word = rt2x00_desc_read(txd, 5); rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); @@ -1538,7 +1541,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); orig_reg = reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -1603,7 +1606,7 @@ static void rt73usb_clear_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &orig_reg); + orig_reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); reg = orig_reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -1691,8 +1694,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, /* * It is now safe to read the descriptor on all architectures. */ - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 1, &word1); + word0 = rt2x00_desc_read(rxd, 0); + word1 = rt2x00_desc_read(rxd, 1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1701,11 +1704,11 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); - _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->iv[0] = _rt2x00_desc_read(rxd, 2); + rxdesc->iv[1] = _rt2x00_desc_read(rxd, 3); rxdesc->dev_flags |= RXDONE_CRYPTO_IV; - _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + rxdesc->icv = _rt2x00_desc_read(rxd, 4); rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* @@ -1768,7 +1771,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -1783,14 +1786,14 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0); rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_G, 0); rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_A, 0); @@ -1806,7 +1809,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); @@ -1814,7 +1817,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); @@ -1830,7 +1833,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); @@ -1858,13 +1861,13 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR0); rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); @@ -1904,13 +1907,13 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read frequency offset. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); /* * Read external LNA informations. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) { __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); @@ -1921,7 +1924,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Store led settings, for correct led behaviour. */ #ifdef CONFIG_RT2X00_LIB_LEDS - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); rt73usb_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); @@ -2188,7 +2191,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR13); rt2x00_set_field32(®, MAC_CSR13_DIR7, 0); rt2x00usb_register_write(rt2x00dev, MAC_CSR13, reg); @@ -2260,7 +2263,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, offset, ®); + reg = rt2x00usb_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, queue->txop); rt2x00usb_register_write(rt2x00dev, offset, reg); @@ -2268,15 +2271,15 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, ®); + reg = rt2x00usb_register_read(rt2x00dev, AIFSN_CSR); rt2x00_set_field32(®, field, queue->aifs); rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg); - rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, ®); + reg = rt2x00usb_register_read(rt2x00dev, CWMIN_CSR); rt2x00_set_field32(®, field, queue->cw_min); rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg); - rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, ®); + reg = rt2x00usb_register_read(rt2x00dev, CWMAX_CSR); rt2x00_set_field32(®, field, queue->cw_max); rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg); @@ -2289,9 +2292,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u64 tsf; u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR13); tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR12); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); return tsf; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index b94479441b0c..170cd504e8ff 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -247,7 +247,10 @@ static const UCHAR b4_default_startup_parms[] = { 0x04, 0x08, /* Noise gain, limit offset */ 0x28, 0x28, /* det rssi, med busy offsets */ 7, /* det sync thresh */ - 0, 2, 2 /* test mode, min, max */ + 0, 2, 2, /* test mode, min, max */ + 0, /* rx/tx delay */ + 0, 0, 0, 0, 0, 0, /* current BSS id */ + 0 /* hop set */ }; /*===========================================================================*/ @@ -597,7 +600,7 @@ static void init_startup_params(ray_dev_t *local) * a_beacon_period = hops a_beacon_period = KuS *//* 64ms = 010000 */ if (local->fw_ver == 0x55) { - memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms, + memcpy(&local->sparm.b4, b4_default_startup_parms, sizeof(struct b4_startup_params)); /* Translate sane kus input values to old build 4/5 format */ /* i = hop time in uS truncated to 3 bytes */ diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 35fe991dcc56..55198ac2b755 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -278,8 +278,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, } if (!priv->is_rtl8187b) { - struct rtl8187_tx_hdr *hdr = - (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); + struct rtl8187_tx_hdr *hdr = skb_push(skb, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; @@ -292,8 +291,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, unsigned int epmap[4] = { 6, 7, 5, 4 }; u16 fc = le16_to_cpu(tx_hdr->frame_control); - struct rtl8187b_tx_hdr *hdr = - (struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr)); + struct rtl8187b_tx_hdr *hdr = skb_push(skb, sizeof(*hdr)); struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); memset(hdr, 0, sizeof(*hdr)); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 39d56313bc94..21e5ef021260 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4952,7 +4952,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (control && control->sta) sta = control->sta; - tx_desc = (struct rtl8xxxu_txdesc32 *)skb_push(skb, tx_desc_size); + tx_desc = skb_push(skb, tx_desc_size); memset(tx_desc, 0, tx_desc_size); tx_desc->pkt_size = cpu_to_le16(pktlen); diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index bdc379178e87..e36ee592c660 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -405,6 +405,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, PS_NULLFUNC_STACK); } + if (rtlpriv->psc.fwctrl_lps) { + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + } hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | @@ -560,6 +564,7 @@ int rtl_init_core(struct ieee80211_hw *hw) spin_lock_init(&rtlpriv->locks.waitq_lock); spin_lock_init(&rtlpriv->locks.entry_list_lock); spin_lock_init(&rtlpriv->locks.c2hcmd_lock); + spin_lock_init(&rtlpriv->locks.scan_list_lock); spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); spin_lock_init(&rtlpriv->locks.check_sendpkt_lock); spin_lock_init(&rtlpriv->locks.fw_ps_lock); @@ -568,6 +573,7 @@ int rtl_init_core(struct ieee80211_hw *hw) /* <5> init list */ INIT_LIST_HEAD(&rtlpriv->entry_list); INIT_LIST_HEAD(&rtlpriv->c2hcmd_list); + INIT_LIST_HEAD(&rtlpriv->scan_list.list); rtlmac->link_state = MAC80211_NOLINK; @@ -578,9 +584,12 @@ int rtl_init_core(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(rtl_init_core); +static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw); + void rtl_deinit_core(struct ieee80211_hw *hw) { rtl_c2hcmd_launcher(hw, 0); + rtl_free_entries_from_scan_list(hw); } EXPORT_SYMBOL_GPL(rtl_deinit_core); @@ -1110,6 +1119,9 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, if (txrate) tcb_desc->hw_rate = txrate->hw_value; + if (rtl_is_tx_report_skb(hw, skb)) + tcb_desc->use_spe_rpt = 1; + if (ieee80211_is_data(fc)) { /* *we set data rate INX 0 @@ -1306,33 +1318,26 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) } EXPORT_SYMBOL_GPL(rtl_action_proc); -static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) +static void setup_special_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc, + int type) { struct ieee80211_hw *hw = rtlpriv->hw; rtlpriv->ra.is_special_data = true; if (rtlpriv->cfg->ops->get_btc_status()) rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( - rtlpriv, 1); + rtlpriv, type); rtl_lps_leave(hw); ppsc->last_delaylps_stamp_jiffies = jiffies; } -/*should call before software enc*/ -u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, - bool is_enc) +static const u8 *rtl_skb_ether_type_ptr(struct ieee80211_hw *hw, + struct sk_buff *skb, bool is_enc) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - __le16 fc = rtl_get_fc(skb); - u16 ether_type; u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); u8 encrypt_header_len = 0; u8 offset; - const struct iphdr *ip; - - if (!ieee80211_is_data(fc)) - goto end; switch (rtlpriv->sec.pairwise_enc_algorithm) { case WEP40_ENCRYPTION: @@ -1352,10 +1357,29 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, offset = mac_hdr_len + SNAP_SIZE; if (is_enc) offset += encrypt_header_len; - ether_type = be16_to_cpup((__be16 *)(skb->data + offset)); + + return skb->data + offset; +} + +/*should call before software enc*/ +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, + bool is_enc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + __le16 fc = rtl_get_fc(skb); + u16 ether_type; + const u8 *ether_type_ptr; + const struct iphdr *ip; + + if (!ieee80211_is_data(fc)) + goto end; + + ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, is_enc); + ether_type = be16_to_cpup((__be16 *)ether_type_ptr); if (ETH_P_IP == ether_type) { - ip = (struct iphdr *)((u8 *)skb->data + offset + + ip = (struct iphdr *)((u8 *)ether_type_ptr + PROTOC_TYPE_SIZE); if (IPPROTO_UDP == ip->protocol) { struct udphdr *udp = (struct udphdr *)((u8 *)ip + @@ -1372,13 +1396,15 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, (is_tx) ? "Tx" : "Rx"); if (is_tx) - setup_arp_tx(rtlpriv, ppsc); + setup_special_tx(rtlpriv, ppsc, + PACKET_DHCP); + return true; } } } else if (ETH_P_ARP == ether_type) { if (is_tx) - setup_arp_tx(rtlpriv, ppsc); + setup_special_tx(rtlpriv, ppsc, PACKET_ARP); return true; } else if (ETH_P_PAE == ether_type) { @@ -1389,6 +1415,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, rtlpriv->ra.is_special_data = true; rtl_lps_leave(hw); ppsc->last_delaylps_stamp_jiffies = jiffies; + + setup_special_tx(rtlpriv, ppsc, PACKET_EAPOL); } return true; @@ -1405,6 +1433,96 @@ end: } EXPORT_SYMBOL_GPL(rtl_is_special_data); +bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + u16 ether_type; + const u8 *ether_type_ptr; + + ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, true); + ether_type = be16_to_cpup((__be16 *)ether_type_ptr); + + /* EAPOL */ + if (ether_type == ETH_P_PAE) + return true; + + return false; +} + +static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + u16 sn; + + sn = atomic_inc_return(&tx_report->sn) & 0x0FFF; + + tx_report->last_sent_sn = sn; + tx_report->last_sent_time = jiffies; + + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, + "Send TX-Report sn=0x%X\n", sn); + + return sn; +} + +void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw) +{ + if (ptcb_desc->use_spe_rpt) { + u16 sn = rtl_get_tx_report_sn(hw); + + SET_TX_DESC_SPE_RPT(pdesc, 1); + SET_TX_DESC_SW_DEFINE(pdesc, sn); + } +} +EXPORT_SYMBOL_GPL(rtl_get_tx_report); + +void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + u16 sn; + + sn = ((tmp_buf[7] & 0x0F) << 8) | tmp_buf[6]; + + tx_report->last_recv_sn = sn; + + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, + "Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n", + tmp_buf[0], sn, tmp_buf[2]); +} +EXPORT_SYMBOL_GPL(rtl_tx_report_handler); + +bool rtl_check_tx_report_acked(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + + if (tx_report->last_sent_sn == tx_report->last_recv_sn) + return true; + + if (time_before(tx_report->last_sent_time + 3 * HZ, jiffies)) { + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_WARNING, + "Check TX-Report timeout!!\n"); + return true; /* 3 sec. (timeout) seen as acked */ + } + + return false; +} + +void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + + for (i = 0; i < wait_ms; i++) { + if (rtl_check_tx_report_acked(hw)) + break; + usleep_range(1000, 2000); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "Wait 1ms (%d/%d) to disable key.\n", i, wait_ms); + } +} /********************************************************* * * functions called by core.c @@ -1469,6 +1587,7 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tid_data *tid_data; struct rtl_sta_info *sta_entry = NULL; + u8 reject_agg; if (sta == NULL) return -EINVAL; @@ -1476,6 +1595,14 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; + if (rtlpriv->cfg->ops->get_btc_status()) { + rtlpriv->btcoexist.btc_ops->btc_get_ampdu_cfg(rtlpriv, + &reject_agg, + NULL, NULL); + if (reject_agg) + return -EINVAL; + } + sta_entry = (struct rtl_sta_info *)sta->drv_priv; if (!sta_entry) return -ENXIO; @@ -1530,6 +1657,24 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw, return 0; } +void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv) +{ + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + u8 reject_agg, ctrl_agg_size = 0, agg_size; + + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_get_ampdu_cfg(rtlpriv, &reject_agg, + &ctrl_agg_size, &agg_size); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "Set RX AMPDU: coex - reject=%d, ctrl_agg_size=%d, size=%d", + reject_agg, ctrl_agg_size, agg_size); + + rtlpriv->hw->max_rx_aggregation_subframes = + (ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF); +} +EXPORT_SYMBOL(rtl_rx_ampdu_apply); + /********************************************************* * * wq & timer callback functions @@ -1564,6 +1709,100 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(rtl_beacon_statistic); +static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_bssid_entry *entry, *next; + + list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) { + list_del(&entry->list); + kfree(entry); + rtlpriv->scan_list.num--; + } +} + +void rtl_scan_list_expire(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_bssid_entry *entry, *next; + unsigned long flags; + + spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags); + + list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) { + /* 180 seconds */ + if (jiffies_to_msecs(jiffies - entry->age) < 180000) + continue; + + list_del(&entry->list); + kfree(entry); + rtlpriv->scan_list.num--; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "BSSID=%pM is expire in scan list (total=%d)\n", + entry->bssid, rtlpriv->scan_list.num); + } + + spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags); + + rtlpriv->btcoexist.btc_info.ap_num = rtlpriv->scan_list.num; +} + +void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flags; + + struct rtl_bssid_entry *entry; + bool entry_found = false; + + /* check if it is scanning */ + if (!mac->act_scanning) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control) && + !ieee80211_is_probe_resp(hdr->frame_control)) + return; + + spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags); + + list_for_each_entry(entry, &rtlpriv->scan_list.list, list) { + if (memcmp(entry->bssid, hdr->addr3, ETH_ALEN) == 0) { + list_del_init(&entry->list); + entry_found = true; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Update BSSID=%pM to scan list (total=%d)\n", + hdr->addr3, rtlpriv->scan_list.num); + break; + } + } + + if (!entry_found) { + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + + if (!entry) + goto label_err; + + memcpy(entry->bssid, hdr->addr3, ETH_ALEN); + rtlpriv->scan_list.num++; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Add BSSID=%pM to scan list (total=%d)\n", + hdr->addr3, rtlpriv->scan_list.num); + } + + entry->age = jiffies; + + list_add_tail(&entry->list, &rtlpriv->scan_list.list); + +label_err: + spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags); +} +EXPORT_SYMBOL(rtl_collect_scan_list); + void rtl_watchdog_wq_callback(void *data) { struct rtl_works *rtlworks = container_of_dwork_rtl(data, @@ -1662,12 +1901,20 @@ void rtl_watchdog_wq_callback(void *data) false; } + /* PS is controlled by coex. */ + if (rtlpriv->cfg->ops->get_btc_status() && + rtlpriv->btcoexist.btc_ops->btc_is_bt_ctrl_lps(rtlpriv)) + goto label_lps_done; + if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) rtl_lps_leave(hw); else rtl_lps_enter(hw); + +label_lps_done: + ; } rtlpriv->link_info.num_rx_inperiod = 0; @@ -1713,6 +1960,9 @@ void rtl_watchdog_wq_callback(void *data) rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); rtlpriv->link_info.bcn_rx_inperiod = 0; + + /* <6> scan list */ + rtl_scan_list_expire(hw); } void rtl_watch_dog_timer_callback(unsigned long data) @@ -1875,8 +2125,7 @@ static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, return NULL; skb_reserve(skb, hw->extra_tx_headroom); - action_frame = (void *)skb_put(skb, 27); - memset(action_frame, 0, 27); + action_frame = skb_put_zero(skb, 27); memcpy(action_frame->da, da, ETH_ALEN); memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); memcpy(action_frame->bssid, bssid, ETH_ALEN); @@ -2005,8 +2254,7 @@ struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, return NULL; skb_reserve(skb, hw->extra_tx_headroom); - action_frame = (void *)skb_put(skb, 34); - memset(action_frame, 0, 34); + action_frame = skb_put_zero(skb, 34); memcpy(action_frame->sa, sa, ETH_ALEN); memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN); memcpy(action_frame->bssid, bssid, ETH_ALEN); diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index 02ff0c5624a7..ab7d81904d25 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -107,6 +107,11 @@ enum ap_peer { SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) +#define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) + int rtl_init_core(struct ieee80211_hw *hw); void rtl_deinit_core(struct ieee80211_hw *hw); void rtl_init_rx_config(struct ieee80211_hw *hw); @@ -123,7 +128,17 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, bool is_enc); +bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw); +void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, + u8 c2h_cmd_len); +bool rtl_check_tx_report_acked(struct ieee80211_hw *hw); +void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms); + void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_scan_list_expire(struct ieee80211_hw *hw); int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -134,6 +149,7 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid); int rtl_rx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid); +void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv); void rtl_watchdog_wq_callback(void *data); void rtl_fwevt_wq_callback(void *data); void rtl_c2hcmd_wq_callback(void *data); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h index 39b9a3309cfd..2ac989a4b2bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h @@ -37,6 +37,28 @@ #include "halbtcoutsrc.h" +/* Interface type */ +#define RT_PCI_INTERFACE 1 +#define RT_USB_INTERFACE 2 +#define RT_SDIO_INTERFACE 3 +#define DEV_BUS_TYPE RT_PCI_INTERFACE + +/* IC type */ +#define RTL_HW_TYPE(adapter) (rtl_hal((struct rtl_priv *)adapter)->hw_type) + +#define IS_NEW_GENERATION_IC(adapter) \ + (RTL_HW_TYPE(adapter) >= HARDWARE_TYPE_RTL8192EE) +#define IS_HARDWARE_TYPE_8812(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8812AE) +#define IS_HARDWARE_TYPE_8821(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8821AE) +#define IS_HARDWARE_TYPE_8723A(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8723AE) +#define IS_HARDWARE_TYPE_8723B(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8723BE) +#define IS_HARDWARE_TYPE_8192E(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8192EE) + #include "halbtc8192e2ant.h" #include "halbtc8723b1ant.h" #include "halbtc8723b2ant.h" diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c index 57e633dbf9a9..44c25724529e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -456,6 +456,39 @@ static void btc8192e2ant_query_bt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } +static +bool btc8192e2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + static void btc8192e2ant_update_bt_link_info(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; @@ -2886,9 +2919,8 @@ void ex_btc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) - btc8192e2ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_2ant) + btc8192e2ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -3078,14 +3110,12 @@ void ex_btc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, */ } -#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) - if ((coex_sta->bt_info_ext & BIT4)) { - /* BT auto report already enabled, do nothing */ - } else { - btc8192e2ant_bt_auto_report(btcoexist, FORCE_EXEC, - true); + if (!btcoexist->auto_report_2ant) { + if (!(coex_sta->bt_info_ext & BIT4)) + btc8192e2ant_bt_auto_report(btcoexist, + FORCE_EXEC, + true); } -#endif } /* check BIT2 first ==> check if bt is under inquiry or page scan */ @@ -3164,7 +3194,7 @@ void ex_btc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, btc8192e2ant_run_coexist_mechanism(btcoexist); } -void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist) +void ex_btc8192e2ant_halt_notify(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -3207,13 +3237,13 @@ void ex_btc8192e2ant_periodical(struct btc_coexist *btcoexist) "************************************************\n"); } -#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) - btc8192e2ant_query_bt_info(btcoexist); - btc8192e2ant_monitor_bt_ctr(btcoexist); - btc8192e2ant_monitor_bt_enable_disable(btcoexist); -#else - if (btc8192e2ant_is_wifi_status_changed(btcoexist) || - coex_dm->auto_tdma_adjust) - btc8192e2ant_run_coexist_mechanism(btcoexist); -#endif + if (!btcoexist->auto_report_2ant) { + btc8192e2ant_query_bt_info(btcoexist); + btc8192e2ant_monitor_bt_ctr(btcoexist); + btc8192e2ant_monitor_bt_enable_disable(btcoexist); + } else { + if (btc8192e2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + btc8192e2ant_run_coexist_mechanism(btcoexist); + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h index fc0fa87ec404..65502acee52c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h @@ -25,8 +25,6 @@ /***************************************************************** * The following is for 8192E 2Ant BT Co-exist definition *****************************************************************/ -#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0 - #define BT_INFO_8192E_2ANT_B_FTP BIT7 #define BT_INFO_8192E_2ANT_B_A2DP BIT6 #define BT_INFO_8192E_2ANT_B_HID BIT5 @@ -166,20 +164,20 @@ struct coex_sta_8192e_2ant { /**************************************************************** * The following is interface which will notify coex module. ****************************************************************/ -void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, +void ex_btc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_btc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length); -void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_display_coex_info(struct btc_coexist *btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 2003c8c51dcc..03998d2e9eb8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -210,11 +210,24 @@ static void halbtc8723b1ant_limited_rx(struct btc_coexist *btcoexist, btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); } +static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + /* trigger */ + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) { u32 reg_hp_txrx, reg_lp_txrx, u32tmp; u32 reg_hp_tx = 0, reg_hp_rx = 0; u32 reg_lp_tx = 0, reg_lp_rx = 0; + static u32 num_of_bt_counter_chk; reg_hp_txrx = 0x770; reg_lp_txrx = 0x774; @@ -232,25 +245,122 @@ static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) coex_sta->low_priority_tx = reg_lp_tx; coex_sta->low_priority_rx = reg_lp_rx; + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + /* reset counter */ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + /* This part is for wifi FW and driver to update BT's status as + * disabled. + * + * The flow is as the following + * 1. disable BT + * 2. if all BT Tx/Rx counter = 0, after 6 sec we query bt info + * 3. Because BT will not rsp from mailbox, so wifi fw will know BT is + * disabled + * + * 4. FW will rsp c2h for BT that driver will know BT is disabled. + */ + if ((reg_hp_tx == 0) && (reg_hp_rx == 0) && (reg_lp_tx == 0) && + (reg_lp_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk == 3) + halbtc8723b1ant_query_bt_info(btcoexist); + } else { + num_of_bt_counter_chk = 0; + } } -static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist) +static void halbtc8723b1ant_monitor_wifi_ctr(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - u8 h2c_parameter[1] = {0}; + s32 wifi_rssi = 0; + bool wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter; + u32 total_cnt; - coex_sta->c2h_bt_info_req_sent = true; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); - /* trigger */ - h2c_parameter[0] |= BIT0; + if (coex_sta->under_ips) { + coex_sta->crc_ok_cck = 0; + coex_sta->crc_ok_11g = 0; + coex_sta->crc_ok_11n = 0; + coex_sta->crc_ok_11n_agg = 0; + + coex_sta->crc_err_cck = 0; + coex_sta->crc_err_11g = 0; + coex_sta->crc_err_11n = 0; + coex_sta->crc_err_11n_agg = 0; + } else { + coex_sta->crc_ok_cck = + btcoexist->btc_read_4byte(btcoexist, 0xf88); + coex_sta->crc_ok_11g = + btcoexist->btc_read_2byte(btcoexist, 0xf94); + coex_sta->crc_ok_11n = + btcoexist->btc_read_2byte(btcoexist, 0xf90); + coex_sta->crc_ok_11n_agg = + btcoexist->btc_read_2byte(btcoexist, 0xfb8); + + coex_sta->crc_err_cck = + btcoexist->btc_read_4byte(btcoexist, 0xf84); + coex_sta->crc_err_11g = + btcoexist->btc_read_2byte(btcoexist, 0xf96); + coex_sta->crc_err_11n = + btcoexist->btc_read_2byte(btcoexist, 0xf92); + coex_sta->crc_err_11n_agg = + btcoexist->btc_read_2byte(btcoexist, 0xfba); + } - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", - h2c_parameter[0]); + /* reset counter */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x0); + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_agg; + + if ((coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > + (total_cnt - coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } - btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; } static bool btc8723b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist) @@ -297,6 +407,7 @@ static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist) bt_link_info->a2dp_exist = coex_sta->a2dp_exist; bt_link_info->pan_exist = coex_sta->pan_exist; bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->bt_hi_pri_link_exist = coex_sta->bt_hi_pri_link_exist; /* work around for HS mode. */ if (bt_hs_on) { @@ -333,6 +444,35 @@ static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist) bt_link_info->hid_only = false; } +static void halbtc8723b1ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8723b1ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, + bool enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + static void btc8723b1ant_set_sw_pen_tx_rate_adapt(struct btc_coexist *btcoexist, bool low_penalty_ra) { @@ -430,6 +570,8 @@ static void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist, static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist, bool force_exec, u8 type) { + coex_sta->coex_table_type = type; + switch (type) { case 0: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, @@ -445,24 +587,68 @@ static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist, break; case 3: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, - 0xaaaaaaaa, 0xffffff, 0x3); + 0x5a5a5a5a, 0xffffff, 0x3); break; case 4: - halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, - 0x5aaa5aaa, 0xffffff, 0x3); + if ((coex_sta->cck_ever_lock) && (coex_sta->scan_ap_num <= 5)) + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5a5a, + 0xffffff, 0x3); + else + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, + 0xffffff, 0x3); break; case 5: - halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, - 0xaaaa5a5a, 0xffffff, 0x3); + if ((coex_sta->cck_ever_lock) && (coex_sta->scan_ap_num <= 5)) + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5aaa5a5a, + 0xffffff, 0x3); + else + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5aaa5a5a, + 0xffffff, 0x3); break; case 6: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, - 0xaaaa5a5a, 0xffffff, 0x3); + 0xaaaaaaaa, 0xffffff, 0x3); break; case 7: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); break; + case 8: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 9: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 10: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 11: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 12: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 13: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 14: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 15: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0xaaaaaaaa, 0xffffff, 0x3); + break; default: break; } @@ -611,14 +797,18 @@ static void halbtc8723b1ant_sw_mechanism(struct btc_coexist *btcoexist, } static void halbtc8723b1ant_set_ant_path(struct btc_coexist *btcoexist, - u8 ant_pos_type, bool init_hw_cfg, - bool wifi_off) + u8 ant_pos_type, bool force_exec, + bool init_hw_cfg, bool wifi_off) { + struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_board_info *board_info = &btcoexist->board_info; - u32 fw_ver = 0, u32tmp = 0; + u32 fw_ver = 0, u32tmp = 0, cnt_bt_cal_chk = 0; bool pg_ext_switch = false; bool use_ext_switch = false; - u8 h2c_parameter[2] = {0}; + bool is_in_mp_mode = false; + u8 h2c_parameter[2] = {0}, u8tmp = 0; + + coex_dm->cur_ant_pos_type = ant_pos_type; btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); /* [31:16] = fw ver, [15:0] = fw sub ver */ @@ -628,24 +818,103 @@ static void halbtc8723b1ant_set_ant_path(struct btc_coexist *btcoexist, use_ext_switch = true; if (init_hw_cfg) { - /*BT select s0/s1 is controlled by WiFi */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + /* WiFi TRx Mask on */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x780); + /* remove due to interrupt is disabled that polling c2h will + * fail and delay 100ms. + */ - /*Force GNT_BT to Normal */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); - } else if (wifi_off) { - /*Force GNT_BT to High */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); - /*BT select s0/s1 is controlled by BT */ + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + } else { + /* set grant_bt to high */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } + /* set wlan_act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* BT select s0/s1 is controlled by BT */ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x39, 0x8, 0x1); + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + } else if (wifi_off) { + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + } else { + /* set grant_bt to high */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } + /* set wlan_act to always low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_IS_IN_MP_MODE, + &is_in_mp_mode); + if (!is_in_mp_mode) + /* BT select s0/s1 is controlled by BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x20, 0x0); + else + /* BT select s0/s1 is controlled by WiFi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x20, 0x1); - /* 0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL - * BT Vendor 0xac = 0xf002 + /* 0x4c[24:23]=00, Set Antenna control by BT_RFE_CTRL + * BT Vendor 0xac=0xf002 */ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); u32tmp &= ~BIT23; u32tmp &= ~BIT24; btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } else { + /* Use H2C to set GNT_BT to LOW */ + if (fw_ver >= 0x180000) { + if (btcoexist->btc_read_1byte(btcoexist, 0x765) != 0) { + h2c_parameter[0] = 0; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + } + } else { + /* BT calibration check */ + while (cnt_bt_cal_chk <= 20) { + u8tmp = btcoexist->btc_read_1byte(btcoexist, + 0x49d); + cnt_bt_cal_chk++; + if (u8tmp & BIT(0)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + mdelay(50); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], ********** BT is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + break; + } + } + + /* set grant_bt to PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x0); + } + + if (btcoexist->btc_read_1byte(btcoexist, 0x76e) != 0xc) { + /* set wlan_act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + } + + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x67, 0x20, + 0x1); /* BT select s0/s1 is controlled by WiFi */ } if (use_ext_switch) { @@ -658,216 +927,278 @@ static void halbtc8723b1ant_set_ant_path(struct btc_coexist *btcoexist, u32tmp |= BIT24; btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + /* fixed internal switch S1->WiFi, S0->BT */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { - /* Main Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x1); - /* tell firmware "no antenna inverse" */ h2c_parameter[0] = 0; - h2c_parameter[1] = 1; /*ext switch type*/ + /* ext switch type */ + h2c_parameter[1] = 1; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } else { - /* Aux Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x0); - /* tell firmware "antenna inverse" */ h2c_parameter[0] = 1; - h2c_parameter[1] = 1; /* ext switch type */ + /* ext switch type */ + h2c_parameter[1] = 1; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } } - /* fixed internal switch first - * fixed internal switch S1->WiFi, S0->BT - */ - if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); - else /* fixed internal switch S0->WiFi, S1->BT */ - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); - - /* ext switch setting */ - switch (ant_pos_type) { - case BTC_ANT_PATH_WIFI: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x1); - else - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x2); - break; - case BTC_ANT_PATH_BT: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x2); - else - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x1); - break; - default: - case BTC_ANT_PATH_PTA: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x1); - else - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x2); - break; + if (force_exec || + (coex_dm->cur_ant_pos_type != coex_dm->pre_ant_pos_type)) { + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x1); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x2); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x2); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x1); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x2); + break; + } } - } else { if (init_hw_cfg) { - /* 0x4c[23] = 1, 0x4c[24] = 0 Antenna control by 0x64 */ + /* 0x4c[23] = 1, 0x4c[24] = 0, + * Antenna control by 0x64 + */ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); u32tmp |= BIT23; u32tmp &= ~BIT24; btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + /* Fix Ext switch Main->S1, Aux->S0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + 0x0); + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { - /* Main Ant to WiFi for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x0); - /* tell firmware "no antenna inverse" */ h2c_parameter[0] = 0; - h2c_parameter[1] = 0; /* internal switch type */ + /* internal switch type */ + h2c_parameter[1] = 0; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } else { - /* Aux Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x1); - /* tell firmware "antenna inverse" */ h2c_parameter[0] = 1; - h2c_parameter[1] = 0; /* internal switch type */ + /* internal switch type */ + h2c_parameter[1] = 0; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } } - /* fixed external switch first - * Main->WiFi, Aux->BT - */ - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, - 0x3, 0x1); - else /* Main->BT, Aux->WiFi */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, - 0x3, 0x2); - - /* internal switch setting */ - switch (ant_pos_type) { - case BTC_ANT_PATH_WIFI: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x0); - else - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x280); - break; - case BTC_ANT_PATH_BT: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x280); - else - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x0); - break; - default: - case BTC_ANT_PATH_PTA: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x200); - else - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x80); - break; + if (force_exec || + (coex_dm->cur_ant_pos_type != coex_dm->pre_ant_pos_type)) { + /* internal switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x0); + else + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x280); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x280); + else + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x0); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x200); + else + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x80); + break; + } } } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; } static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, bool turn_on, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool wifi_busy = false; u8 rssi_adjust_val = 0; + u8 ps_tdma_byte0_val = 0x51; + u8 ps_tdma_byte3_val = 0x10; + u8 ps_tdma_byte4_val = 0x50; + s8 wifi_duration_adjust = 0x0; + static bool pre_wifi_busy; coex_dm->cur_ps_tdma_on = turn_on; coex_dm->cur_ps_tdma = type; btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); - if (!force_exec) { - if (coex_dm->cur_ps_tdma_on) - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ******** TDMA(on, %d) *********\n", - coex_dm->cur_ps_tdma); - else - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ******** TDMA(off, %d) ********\n", - coex_dm->cur_ps_tdma); + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + if (!force_exec) { if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) return; } + + if (coex_sta->scan_ap_num <= 5) { + wifi_duration_adjust = 5; + + if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } else if (coex_sta->scan_ap_num >= 40) { + wifi_duration_adjust = -15; + + if (coex_sta->a2dp_bit_pool < 35) + wifi_duration_adjust = -5; + else if (coex_sta->a2dp_bit_pool < 45) + wifi_duration_adjust = -10; + } else if (coex_sta->scan_ap_num >= 20) { + wifi_duration_adjust = -10; + + if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } else { + wifi_duration_adjust = 0; + + if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } + + if ((type == 1) || (type == 2) || (type == 9) || (type == 11) || + (type == 101) || (type == 102) || (type == 109) || (type == 101)) { + if (!coex_sta->force_lps_on) { + /* Native power save TDMA, only for A2DP-only case + * 1/2/9/11 while wifi noisy threshold > 30 + */ + + /* no null-pkt */ + ps_tdma_byte0_val = 0x61; + /* no tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x11; + /* 0x778 = d/1 toggle, no dynamic slot */ + ps_tdma_byte4_val = 0x10; + } else { + /* null-pkt */ + ps_tdma_byte0_val = 0x51; + /* tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x10; + /* 0x778 = d/1 toggle, dynamic slot */ + ps_tdma_byte4_val = 0x50; + } + } else if ((type == 3) || (type == 13) || (type == 14) || + (type == 103) || (type == 113) || (type == 114)) { + /* null-pkt */ + ps_tdma_byte0_val = 0x51; + /* tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x10; + /* 0x778 = d/1 toggle, no dynamic slot */ + ps_tdma_byte4_val = 0x10; + } else { /* native power save case */ + /* no null-pkt */ + ps_tdma_byte0_val = 0x61; + /* no tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x11; + /* 0x778 = d/1 toggle, no dynamic slot */ + ps_tdma_byte4_val = 0x11; + /* psTdmaByte4Va is not define for 0x778 = d/1, 1/1 case */ + } + + /* if (bt_link_info->slave_role) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + ps_tdma_byte4_val = ps_tdma_byte4_val | 0x1; + + if (type > 100) { + /* set antenna control by SW */ + ps_tdma_byte0_val = ps_tdma_byte0_val | 0x82; + /* set antenna no toggle, control by antenna diversity */ + ps_tdma_byte3_val = ps_tdma_byte3_val | 0x60; + } + if (turn_on) { switch (type) { default: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a, - 0x1a, 0x0, 0x50); + 0x1a, 0x0, + ps_tdma_byte4_val); break; case 1: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x3a, - 0x03, 0x10, 0x50); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x3a + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); rssi_adjust_val = 11; break; case 2: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x2b, - 0x03, 0x10, 0x50); - rssi_adjust_val = 14; + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x2d + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 3: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d, - 0x1d, 0x0, 0x52); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x30, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 4: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, - 0x3, 0x14, 0x0); - rssi_adjust_val = 17; + 0x3, 0x14, 0x0); break; case 5: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, - 0x3, 0x11, 0x10); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x1f, 0x3, + ps_tdma_byte3_val, 0x11); break; case 6: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20, - 0x3, 0x11, 0x13); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x20, 0x3, + ps_tdma_byte3_val, 0x11); break; case 7: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc, @@ -875,33 +1206,44 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, break; case 8: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, - 0x3, 0x10, 0x0); + 0x3, 0x10, 0x0); break; case 9: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, - 0x3, 0x10, 0x50); - rssi_adjust_val = 18; + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 10: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, 0xa, 0x0, 0x40); break; case 11: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, - 0x03, 0x10, 0x50); - rssi_adjust_val = 20; + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 12: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a, - 0x0a, 0x0, 0x50); + 0x0a, 0x0, 0x50); break; case 13: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, - 0x15, 0x0, 0x50); + if (coex_sta->scan_ap_num <= 3) + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x40, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + else + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 14: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, - 0x3, 0x10, 0x52); + if (coex_sta->scan_ap_num <= 3) + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, 0x51, 0x30, 0x3, 0x10, 0x50); + else + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 15: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, @@ -909,103 +1251,173 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, break; case 16: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, - 0x3, 0x10, 0x0); - rssi_adjust_val = 18; + 0x3, 0x10, 0x0); break; case 18: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, - 0x3, 0x10, 0x0); - rssi_adjust_val = 14; + 0x3, 0x10, 0x0); break; case 20: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35, - 0x03, 0x11, 0x10); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x3f, 0x03, + ps_tdma_byte3_val, 0x10); break; case 21: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, - 0x03, 0x11, 0x11); + 0x03, 0x11, 0x11); break; case 22: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, - 0x03, 0x11, 0x10); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x10); break; case 23: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, - 0x3, 0x31, 0x18); - rssi_adjust_val = 22; + 0x3, 0x31, 0x18); break; case 24: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, - 0x3, 0x31, 0x18); - rssi_adjust_val = 22; + 0x3, 0x31, 0x18); break; case 25: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); - rssi_adjust_val = 22; break; case 26: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); - rssi_adjust_val = 22; break; case 27: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, - 0x3, 0x31, 0x98); - rssi_adjust_val = 22; + 0x3, 0x31, 0x98); break; case 28: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25, - 0x3, 0x31, 0x0); + 0x3, 0x31, 0x0); break; case 29: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a, - 0x1a, 0x1, 0x10); + 0x1a, 0x1, 0x10); break; case 30: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, - 0x3, 0x10, 0x50); + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x30, + 0x3, 0x10, 0x10); break; case 31: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a, - 0x1a, 0, 0x58); + 0x1a, 0, 0x58); break; case 32: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa, - 0x3, 0x10, 0x0); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x35, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 33: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25, - 0x3, 0x30, 0x90); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x35, 0x3, + ps_tdma_byte3_val, 0x10); break; case 34: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a, - 0x1a, 0x0, 0x10); + 0x1a, 0x0, 0x10); break; case 35: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a, - 0x1a, 0x0, 0x10); + 0x1a, 0x0, 0x10); break; case 36: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, - 0x3, 0x14, 0x50); + 0x3, 0x14, 0x50); break; - /* SoftAP only with no sta associated, BT disable, - * TDMA mode for power saving - * here softap mode screen off will cost 70-80mA for phone - */ case 40: + /* SoftAP only with no sta associated,BT disable ,TDMA + * mode for power saving + * + * here softap mode screen off will cost 70-80mA for + * phone + */ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18, - 0x00, 0x10, 0x24); + 0x00, 0x10, 0x24); + break; + + case 101: + /* for 1-Ant translate to 2-Ant */ + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x3a + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 102: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x2d + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 103: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x3a, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 105: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x15, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 106: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x20, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 109: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 111: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 113: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 114: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 120: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x3f, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 122: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 132: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 133: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x11); break; } } else { + /* disable PS tdma */ switch (type) { case 8: /* PTA Control */ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0, 0x0, 0x0, 0x0); halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); break; case 0: @@ -1013,17 +1425,10 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, /* Software control, Antenna at BT side */ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, 0x0, 0x0); - halbtc8723b1ant_set_ant_path(btcoexist, - BTC_ANT_PATH_BT, - false, false); break; - case 9: - /* Software control, Antenna at WiFi side */ - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, - 0x0, 0x0, 0x0); - halbtc8723b1ant_set_ant_path(btcoexist, - BTC_ANT_PATH_WIFI, - false, false); + case 1: /* 2-Ant, 0x778=3, antenna control by ant diversity */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x48, 0x0); break; } } @@ -1037,8 +1442,191 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; } +void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, + u8 wifi_status) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static s32 up, dn, m, n, wait_count; + /* 0: no change, +1: increase WiFi duration, + * -1: decrease WiFi duration + */ + s32 result; + u8 retry_count = 0, bt_info_ext; + bool wifi_busy = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], TdmaDurationAdjustForAcl()\n"); + + if (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY) + wifi_busy = true; + else + wifi_busy = false; + + if ((wifi_status == + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN) || + (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN) || + (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT)) { + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + + result = 0; + wait_count++; + /* no retry in the last 2-second duration */ + if (retry_count == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + /* if retry count during continuous n*2 seconds + * is 0, enlarge WiFi duration + */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Increase wifi duration!!\n"); + } + } else if (retry_count <= 3) { + /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + /* if continuous 2 retry count(every 2 seconds) + * >0 and < 3, reduce WiFi duration + */ + if (wait_count <= 2) + /* avoid loop between the two levels */ + m++; + else + m = 1; + + if (m >= 20) + /* maximum of m = 20 ' will recheck if + * need to adjust wifi duration in + * maximum time interval 120 seconds + */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); + } + } else { + /* retry count > 3, once retry count > 3, to reduce + * WiFi duration + */ + if (wait_count == 1) + /* to avoid loop between the two levels */ + m++; + else + m = 1; + + if (m >= 20) + /* maximum of m = 20 ' will recheck if need to + * adjust wifi duration in maximum time interval + * 120 seconds + */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } + } + + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + } + } +} + static void halbtc8723b1ant_ps_tdma_chk_pwr_save(struct btc_coexist *btcoexist, - bool new_ps_state) + bool new_ps_state) { u8 lps_mode = 0x0; @@ -1078,6 +1666,7 @@ static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist, btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + coex_sta->force_lps_on = false; break; case BTC_PS_LPS_ON: halbtc8723b1ant_ps_tdma_chk_pwr_save(btcoexist, true); @@ -1089,27 +1678,95 @@ static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist, &low_pwr_disable); /* power save must executed before psTdma */ btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + coex_sta->force_lps_on = true; break; case BTC_PS_LPS_OFF: halbtc8723b1ant_ps_tdma_chk_pwr_save(btcoexist, false); btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + coex_sta->force_lps_on = false; break; default: break; } } +static void halbtc8723b1ant_action_wifi_only(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); +} + +/* check if BT is disabled */ +static void halbtc8723b1ant_monitor_bt_enable_disable(struct btc_coexist + *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u32 bt_disable_cnt; + bool bt_active = true, bt_disabled = false; + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + } else { + bt_disable_cnt++; + if (bt_disable_cnt >= 2) + bt_disabled = true; + } + if (coex_sta->bt_disabled != bt_disabled) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + + coex_sta->bt_disabled = bt_disabled; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + if (bt_disabled) { + halbtc8723b1ant_action_wifi_only(btcoexist); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + /***************************************************** * * Non-Software Coex Mechanism start * *****************************************************/ + +static void halbtc8723b1ant_action_bt_whck_test(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist) { halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } @@ -1123,35 +1780,56 @@ static void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool wifi_connected = false, ap_enable = false; + bool wifi_busy = false, bt_busy = false; btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &ap_enable); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); - if (!wifi_connected) { - halbtc8723b1ant_power_save_state(btcoexist, - BTC_PS_WIFI_NATIVE, 0x0, 0x0); + if (coex_sta->bt_abnormal_scan) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else if (!wifi_connected && !coex_sta->wifi_is_high_pri_task) { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); - } else if (bt_link_info->sco_exist || bt_link_info->hid_only) { - /* SCO/HID-only busy */ + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (bt_link_info->sco_exist || bt_link_info->hid_exist || + bt_link_info->a2dp_exist) { + /* SCO/HID/A2DP busy */ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - } else { - if (ap_enable) - halbtc8723b1ant_power_save_state(btcoexist, - BTC_PS_WIFI_NATIVE, - 0x0, 0x0); + if (coex_sta->c2h_bt_remote_name_req) + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); else - halbtc8723b1ant_power_save_state(btcoexist, - BTC_PS_LPS_ON, - 0x50, 0x4); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist || wifi_busy) { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + if (coex_sta->c2h_bt_remote_name_req) + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); + else + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); } } @@ -1167,7 +1845,7 @@ static void btc8723b1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, /* tdma and coex table */ if (bt_link_info->sco_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); } else { /* HID */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); @@ -1181,6 +1859,10 @@ static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + if ((coex_sta->low_priority_rx >= 950) && (!coex_sta->under_ips)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; if (bt_link_info->hid_only) { /* HID */ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, wifi_status); @@ -1189,39 +1871,40 @@ static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( } else if (bt_link_info->a2dp_only) { /* A2DP */ if (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 8); + true, 32); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); coex_dm->auto_tdma_adjust = false; - } else { /* for low BT RSSI */ - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 11); + } else { + btc8723b1ant_tdma_dur_adj_for_acl(btcoexist, + wifi_status); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust = true; } - } else if (bt_link_info->hid_exist && - bt_link_info->a2dp_exist) { /* HID + A2DP */ + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { + /* A2DP + PAN(OPP,FTP), HID + A2DP + PAN(OPP,FTP) */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) { + /* HID + A2DP */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); coex_dm->auto_tdma_adjust = false; - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); - /* PAN(OPP,FTP), HID + PAN(OPP,FTP) */ + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); } else if (bt_link_info->pan_only || - (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + /* PAN(OPP,FTP), HID + PAN(OPP,FTP) */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); - coex_dm->auto_tdma_adjust = false; - /* A2DP + PAN(OPP,FTP), HID + A2DP + PAN(OPP,FTP) */ - } else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) || - (bt_link_info->hid_exist && bt_link_info->a2dp_exist && - bt_link_info->pan_exist)) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); coex_dm->auto_tdma_adjust = false; } else { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + /* BT no-profile busy (0x9) */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); coex_dm->auto_tdma_adjust = false; } } @@ -1233,7 +1916,9 @@ static void btc8723b1ant_action_wifi_not_conn(struct btc_coexist *btcoexist) 0x0, 0x0); /* tdma and coex table */ - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); } @@ -1246,30 +1931,31 @@ btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoexist) 0x0, 0x0); /* tdma and coex table */ - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { + if (bt_link_info->a2dp_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 22); + true, 32); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } else if (bt_link_info->pan_only) { + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 20); + true, 22); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)){ + } else if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY){ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } @@ -1282,14 +1968,19 @@ btc8723b1ant_act_wifi_not_conn_asso_auth(struct btc_coexist *btcoexist) halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || - (bt_link_info->sco_exist) || (bt_link_info->hid_only) || - (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); - } else { + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else if (bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); } } @@ -1301,30 +1992,32 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) 0x0, 0x0); /* tdma and coex table */ - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { + if (bt_link_info->a2dp_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 22); + true, 32); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } else if (bt_link_info->pan_only) { + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 20); + true, 22); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); + NORMAL_EXEC, 4); } - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + } else if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) { btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } @@ -1332,23 +2025,34 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) static void halbtc8723b1ant_action_wifi_connected_special_packet( struct btc_coexist *btcoexist) { - bool hs_connecting = false; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_busy = false; - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* no special packet process for both WiFi and BT very busy */ + if ((wifi_busy) && + ((bt_link_info->pan_exist) || (coex_sta->num_of_profile >= 2))) + return; halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); /* tdma and coex table */ - if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || - (bt_link_info->sco_exist) || (bt_link_info->hid_only) || - (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); - } else { + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (bt_link_info->a2dp_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } @@ -1391,12 +2095,31 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); /* power save state */ if (!ap_enable && - BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY && !btcoexist->bt_link_info.hid_only) { - if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) - halbtc8723b1ant_power_save_state(btcoexist, + if (btcoexist->bt_link_info.a2dp_only) { + if (!wifi_busy) { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } else { /* busy */ + if (coex_sta->scan_ap_num >= + BT_8723B_1ANT_WIFI_NOISY_THRESH) + /* no force LPS, no PS-TDMA, + * use pure TDMA + */ + halbtc8723b1ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8723b1ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + } else if ((!coex_sta->pan_exist) && (!coex_sta->a2dp_exist) && + (!coex_sta->hid_exist)) + halbtc8723b1ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); else halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, @@ -1407,36 +2130,44 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) } /* tdma and coex table */ if (!wifi_busy) { - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, - BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == - coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) { btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } else { - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, - BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == - coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) { btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 8); + true, 32); + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); } } } @@ -1445,12 +2176,15 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - bool wifi_connected = false, bt_hs_on = false; + bool wifi_connected = false, bt_hs_on = false, wifi_busy = false; bool increase_scan_dev_num = false; bool bt_ctrl_agg_buf_size = false; + bool miracast_plus_bt = false; u8 agg_buf_size = 5; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; + u32 wifi_bw; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], RunCoexistMechanism()===>\n"); @@ -1473,54 +2207,99 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) return; } - if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { - increase_scan_dev_num = true; + if (coex_sta->bt_whck_test) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi is under IPS !!!\n"); + halbtc8723b1ant_action_bt_whck_test(btcoexist); + return; } + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) + increase_scan_dev_num = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, &increase_scan_dev_num); - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status >> 16; - if (num_of_wifi_link >= 2) { - halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + if (num_of_wifi_link >= 2 || + wifi_link_status & WIFI_P2P_GO_CONNECTED) { + if (bt_link_info->bt_link_exist) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, - bt_ctrl_agg_buf_size, - agg_buf_size); - halbtc8723b1ant_action_wifi_multiport(btcoexist); + bt_ctrl_agg_buf_size, agg_buf_size); + + if ((bt_link_info->a2dp_exist || wifi_busy) && + (coex_sta->c2h_bt_inquiry_page)) + halbtc8723b1ant_action_bt_inquiry(btcoexist); + else + halbtc8723b1ant_action_wifi_multiport(btcoexist); + return; } - if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { - halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (bt_link_info->bt_link_exist && wifi_connected) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + if (iot_peer != BTC_IOT_PEER_CISCO && + iot_peer != BTC_IOT_PEER_BROADCOM) { + if (bt_link_info->sco_exist) + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, + false, 0x5); + else + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, + false, 0x5); + } else { + if (bt_link_info->sco_exist) { + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, + false, 0x5); + } else { + if (wifi_bw == BTC_WIFI_BW_HT40) + halbtc8723b1ant_limited_rx( + btcoexist, NORMAL_EXEC, false, + true, 0x10); + else + halbtc8723b1ant_limited_rx( + btcoexist, NORMAL_EXEC, false, + true, 0x8); + } + } + + halbtc8723b1ant_sw_mechanism(btcoexist, true); } else { - if (wifi_connected) - halbtc8723b1ant_limited_tx(btcoexist, - NORMAL_EXEC, 1, 1, 1, 1); - else - halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, - 0, 0, 0, 0); - } + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); - if (bt_link_info->sco_exist) { - bt_ctrl_agg_buf_size = true; - agg_buf_size = 0x3; - } else if (bt_link_info->hid_exist) { - bt_ctrl_agg_buf_size = true; - agg_buf_size = 0x5; - } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { - bt_ctrl_agg_buf_size = true; - agg_buf_size = 0x8; - } - halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, - bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + halbtc8723b1ant_sw_mechanism(btcoexist, false); + } btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); if (coex_sta->c2h_bt_inquiry_page) { @@ -1556,91 +2335,141 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } +/* force coex mechanism to reset */ static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) { /* sw all off */ halbtc8723b1ant_sw_mechanism(btcoexist, false); - halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + coex_sta->pop_event_cnt = 0; } static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, - bool backup) + bool backup, bool wifi_only) { struct rtl_priv *rtlpriv = btcoexist->adapter; u32 u32tmp = 0; - u8 u8tmp = 0; - u32 cnt_bt_cal_chk = 0; + u8 u8tmpa = 0, u8tmpb = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], 1Ant Init HW Config!!\n"); - if (backup) {/* backup rf 0x1e value */ - coex_dm->backup_arfr_cnt1 = - btcoexist->btc_read_4byte(btcoexist, 0x430); - coex_dm->backup_arfr_cnt2 = - btcoexist->btc_read_4byte(btcoexist, 0x434); - coex_dm->backup_retry_limit = - btcoexist->btc_read_2byte(btcoexist, 0x42a); - coex_dm->backup_ampdu_max_time = - btcoexist->btc_read_1byte(btcoexist, 0x456); - } - - /* WiFi goto standby while GNT_BT 0-->1 */ - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); - /* BT goto standby while GNT_BT 1-->0 */ - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500); - - btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); - btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); - - /* BT calibration check */ - while (cnt_bt_cal_chk <= 20) { - u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d); - cnt_bt_cal_chk++; - if (u32tmp & BIT0) { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ########### BT calibration(cnt=%d) ###########\n", - cnt_bt_cal_chk); - mdelay(50); - } else { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ********** BT NOT calibration (cnt=%d)**********\n", - cnt_bt_cal_chk); - break; - } - } + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = + (btcoexist->btc_read_1byte(btcoexist, 0xf1) & 0xf0) >> 4; + /* enable TBTT interrupt */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, 0x1); /* 0x790[5:0] = 0x5 */ - u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); - u8tmp &= 0xc0; - u8tmp |= 0x5; - btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); /* Enable counter statistics */ - /*0x76e[3] = 1, WLAN_Act control by PTA */ - btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + /* Antenna config */ - halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, true, false); + if (wifi_only) + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, true, false); + else + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, true, false); + /* PTA parameter */ halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + u32tmp, u8tmpa, u8tmpb); } /************************************************************** - * extern function start with ex_halbtc8723b1ant_ + * extern function start with ex_btc8723b1ant_ **************************************************************/ +void ex_btc8723b1ant_power_on_setting(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "xxxxxxxxxxxxxxxx Execute 8723b 1-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + + btcoexist->stop_coex_dm = true; + + btcoexist->btc_write_1byte(btcoexist, 0x67, 0x20); + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT0 | BIT1); + + /* set GRAN_BT = 1 */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + /* set WLAN_ACT = 0 */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* S0 or S1 setting and Local register setting(By the setting fw can get + * ant number, S0/S1, ... info) + * + * Local setting bit define + * BIT0: "0" for no antenna inverse; "1" for antenna inverse + * BIT1: "0" for internal switch; "1" for external switch + * BIT2: "0" for one antenna; "1" for two antenna + * NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and + * BIT2 = 0 + */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); -void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist) + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x280); + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + value = 1; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + u8tmp |= 0x1; /* antenna inverse */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + value = 0; + } + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + &value); + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + + +void ex_btc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only) { - halbtc8723b1ant_init_hw_config(btcoexist, true); + halbtc8723b1ant_init_hw_config(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = false; } -void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -1654,7 +2483,7 @@ void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) halbtc8723b1ant_query_bt_info(btcoexist); } -void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) { struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; @@ -1687,11 +2516,6 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) "\r\n =========================================="); } - if (!board_info->bt_exist) { - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); - return; - } - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", board_info->pg_ant_num, board_info->btdm_ant_num, @@ -1760,7 +2584,7 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", - ((btcoexist->bt_info.bt_disabled) ? ("disabled") : + ((coex_sta->bt_disabled) ? ("disabled") : ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) ? @@ -1835,6 +2659,9 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) coex_dm->error_condition); } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d", + "Coex Table Type", coex_sta->coex_table_type); + /* Hw setting */ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); @@ -1926,13 +2753,12 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) - halbtc8723b1ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_1ant) + halbtc8723b1ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } -void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -1945,7 +2771,7 @@ void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) coex_sta->under_ips = true; halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, - false, true); + FORCE_EXEC, false, true); /* set PTA control */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); halbtc8723b1ant_coex_table_with_type(btcoexist, @@ -1955,13 +2781,13 @@ void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], IPS LEAVE notify\n"); coex_sta->under_ips = false; - halbtc8723b1ant_init_hw_config(btcoexist, false); + halbtc8723b1ant_init_hw_config(btcoexist, false, false); halbtc8723b1ant_init_coex_dm(btcoexist); halbtc8723b1ant_query_bt_info(btcoexist); } } -void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -1979,17 +2805,45 @@ void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; + u8 u8tmpa, u8tmpb; + u32 u32tmp; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; bool bt_ctrl_agg_buf_size = false; u8 agg_buf_size = 5; - if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == BTC_SCAN_START) { + coex_sta->wifi_is_high_pri_task = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN START notify\n"); + /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN FINISH notify\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + } + + if (coex_sta->bt_disabled) return; btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); @@ -2037,19 +2891,38 @@ void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; - bool bt_ctrl_agg_buf_size = false; + bool bt_ctrl_agg_buf_size = false, under_4way = false; u8 agg_buf_size = 5; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + coex_sta->bt_disabled) return; + if (type == BTC_ASSOCIATE_START) { + coex_sta->wifi_is_high_pri_task = true; + + /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT START notify\n"); + coex_dm->arp_cnt = 0; + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT FINISH notify\n"); + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status>>16; @@ -2088,33 +2961,68 @@ void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, - u8 type) +void ex_btc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 h2c_parameter[3] = {0}; u32 wifi_bw; - u8 wifiCentralChnl; + u8 wifi_central_chnl; + bool wifi_under_b_mode = false; if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + coex_sta->bt_disabled) return; - if (BTC_MEDIA_CONNECT == type) + if (type == BTC_MEDIA_CONNECT) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], MEDIA connect notify\n"); - else + /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = + btcoexist->btc_read_4byte(btcoexist, 0x430); + coex_dm->backup_arfr_cnt2 = + btcoexist->btc_read_4byte(btcoexist, 0x434); + coex_dm->backup_retry_limit = + btcoexist->btc_read_2byte(btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = + btcoexist->btc_read_1byte(btcoexist, 0x456); + } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], MEDIA disconnect notify\n"); + coex_dm->arp_cnt = 0; + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } /* only 2.4G we need to inform bt the chnl mask */ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, - &wifiCentralChnl); + &wifi_central_chnl); - if ((BTC_MEDIA_CONNECT == type) && - (wifiCentralChnl <= 14)) { + if (type == BTC_MEDIA_CONNECT && wifi_central_chnl <= 14) { h2c_parameter[0] = 0x0; - h2c_parameter[1] = wifiCentralChnl; + h2c_parameter[1] = wifi_central_chnl; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); if (BTC_WIFI_BW_HT40 == wifi_bw) h2c_parameter[2] = 0x30; @@ -2134,20 +3042,53 @@ void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); } -void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type) +void ex_btc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool bt_hs_on = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; - bool bt_ctrl_agg_buf_size = false; + bool bt_ctrl_agg_buf_size = false, under_4way = false; u8 agg_buf_size = 5; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + coex_sta->bt_disabled) return; + if (type == BTC_PACKET_DHCP || type == BTC_PACKET_EAPOL || + type == BTC_PACKET_ARP) { + if (type == BTC_PACKET_ARP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], special Packet ARP notify\n"); + + coex_dm->arp_cnt++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + + if ((coex_dm->arp_cnt >= 10) && (!under_4way)) + /* if APR PKT > 10 after connect, do not go to + * ActionWifiConnectedSpecificPacket(btcoexist) + */ + coex_sta->wifi_is_high_pri_task = false; + else + coex_sta->wifi_is_high_pri_task = true; + } else { + coex_sta->wifi_is_high_pri_task = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], special Packet DHCP or EAPOL notify\n"); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], special Packet [Type = %d] notify\n", + type); + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status >> 16; @@ -2178,8 +3119,8 @@ void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, } } -void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmp_buf, u8 length) +void ex_btc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 bt_info = 0; @@ -2209,16 +3150,58 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, "0x%02x, ", tmp_buf[i]); } - if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) { - coex_sta->bt_retry_cnt = /* [3:0] */ + /* if 0xff, it means BT is under WHCK test */ + if (bt_info == 0xff) + coex_sta->bt_whck_test = true; + else + coex_sta->bt_whck_test = false; + + if (rsp_source != BT_INFO_SRC_8723B_1ANT_WIFI_FW) { + coex_sta->bt_retry_cnt = /* [3:0] */ coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_remote_name_req = true; + else + coex_sta->c2h_bt_remote_name_req = false; + coex_sta->bt_rssi = - coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + coex_sta->bt_info_c2h[rsp_source][3] * 2 - 90; coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + if (coex_sta->bt_info_c2h[rsp_source][1] == 0x49) { + coex_sta->a2dp_bit_pool = + coex_sta->bt_info_c2h[rsp_source][6]; + } else { + coex_sta->a2dp_bit_pool = 0; + } + + coex_sta->bt_tx_rx_mask = + (coex_sta->bt_info_c2h[rsp_source][2] & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + + if (!coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG + * 0x3C != 0x15 => Need to switch BT TRx Mask + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x15); + + /* BT TRx Mask lock 0x2c[0], 0x30[0] = 0 */ + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x2c, 0x7c44); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x30, 0x7c44); + } + /* Here we need to resend some wifi info to BT * because bt is reset and loss of the info. */ @@ -2228,11 +3211,11 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); if (wifi_connected) - ex_halbtc8723b1ant_media_status_notify(btcoexist, - BTC_MEDIA_CONNECT); + ex_btc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_CONNECT); else - ex_halbtc8723b1ant_media_status_notify(btcoexist, - BTC_MEDIA_DISCONNECT); + ex_btc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); } if (coex_sta->bt_info_ext & BIT3) { @@ -2247,14 +3230,15 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, } else { /* BT already NOT ignore Wlan active, do nothing here.*/ } -#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) - if (coex_sta->bt_info_ext & BIT4) { - /* BT auto report already enabled, do nothing */ - } else { - halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC, - true); + if (!btcoexist->auto_report_1ant) { + if (coex_sta->bt_info_ext & BIT4) { + /* BT auto report already enabled, do nothing */ + } else { + halbtc8723b1ant_bt_auto_report(btcoexist, + FORCE_EXEC, + true); + } } -#endif } /* check BIT2 first ==> check if bt is under inquiry or page scan */ @@ -2263,6 +3247,8 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, else coex_sta->c2h_bt_inquiry_page = false; + coex_sta->num_of_profile = 0; + /* set link exist status */ if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { coex_sta->bt_link_exist = false; @@ -2270,30 +3256,77 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->a2dp_exist = false; coex_sta->hid_exist = false; coex_sta->sco_exist = false; + + coex_sta->bt_hi_pri_link_exist = false; } else { /* connection exists */ coex_sta->bt_link_exist = true; - if (bt_info & BT_INFO_8723B_1ANT_B_FTP) + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) { coex_sta->pan_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->pan_exist = false; - if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) + } + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) { coex_sta->a2dp_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->a2dp_exist = false; - if (bt_info & BT_INFO_8723B_1ANT_B_HID) + } + if (bt_info & BT_INFO_8723B_1ANT_B_HID) { coex_sta->hid_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->hid_exist = false; - if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) + } + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) { coex_sta->sco_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->sco_exist = false; + } + + if ((!coex_sta->hid_exist) && + (!coex_sta->c2h_bt_inquiry_page) && + (!coex_sta->sco_exist)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= + 160) { + coex_sta->hid_exist = true; + coex_sta->wrong_profile_notification++; + coex_sta->num_of_profile++; + bt_info = bt_info | 0x28; + } + } + + /* Add Hi-Pri Tx/Rx counter to avoid false detection */ + if (((coex_sta->hid_exist) || (coex_sta->sco_exist)) && + (coex_sta->high_priority_tx + coex_sta->high_priority_rx >= + 160) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->bt_hi_pri_link_exist = true; + + if ((bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) && + (coex_sta->num_of_profile == 0)) { + if (coex_sta->low_priority_tx + + coex_sta->low_priority_rx >= + 160) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + coex_sta->wrong_profile_notification++; + bt_info = bt_info | 0x88; + } + } } halbtc8723b1ant_update_bt_link_info(btcoexist); - if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) { + /* mask profile bit for connect-ilde identification + * ( for CSR case: A2DP idle --> 0x41) + */ + bt_info = bt_info & 0x1f; + + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT Non-Connected idle!\n"); @@ -2315,8 +3348,7 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); } else { - coex_dm->bt_status = - BT_8723B_1ANT_BT_STATUS_MAX; + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_MAX; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n"); } @@ -2332,7 +3364,44 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, halbtc8723b1ant_run_coexist_mechanism(btcoexist); } -void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u32 u32tmp; + u8 u8tmpa, u8tmpb, u8tmpc; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF Status notify\n"); + + if (type == BTC_RF_ON) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned ON!!\n"); + btcoexist->stop_coex_dm = false; + } else if (type == BTC_RF_OFF) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned OFF!!\n"); + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + + halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + btcoexist->stop_coex_dm = true; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmpc = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x, 0x76e=0x%x\n", + u32tmp, u8tmpa, u8tmpb, u8tmpc); + } +} + +void ex_btc8723b1ant_halt_notify(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -2340,7 +3409,8 @@ void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) btcoexist->stop_coex_dm = true; - halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, FORCE_EXEC, + false, true); halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); @@ -2348,10 +3418,12 @@ void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); - ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + ex_btc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; } -void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -2360,81 +3432,66 @@ void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) if (BTC_WIFI_PNP_SLEEP == pnp_state) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to SLEEP\n"); - btcoexist->stop_coex_dm = true; - halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, - true); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + /* Driver do not leave IPS/LPS when driver is going to sleep, so + * BTCoexistence think wifi is still under IPS/LPS + * + * BT should clear UnderIPS/UnderLPS state to avoid mismatch + * state after wakeup. + */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + btcoexist->stop_coex_dm = true; } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to WAKE UP\n"); btcoexist->stop_coex_dm = false; - halbtc8723b1ant_init_hw_config(btcoexist, false); + halbtc8723b1ant_init_hw_config(btcoexist, false, false); halbtc8723b1ant_init_coex_dm(btcoexist); halbtc8723b1ant_query_bt_info(btcoexist); } } -void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], *****************Coex DM Reset****************\n"); - halbtc8723b1ant_init_hw_config(btcoexist, false); - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0); + halbtc8723b1ant_init_hw_config(btcoexist, false, false); halbtc8723b1ant_init_coex_dm(btcoexist); } -void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - struct btc_board_info *board_info = &btcoexist->board_info; - struct btc_stack_info *stack_info = &btcoexist->stack_info; - static u8 dis_ver_info_cnt; - u32 fw_ver = 0, bt_patch_ver = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], ==========================Periodical===========================\n"); - if (dis_ver_info_cnt <= 5) { - dis_ver_info_cnt += 1; - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", - board_info->pg_ant_num, board_info->btdm_ant_num, - board_info->btdm_ant_pos); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], BT stack/ hci ext ver = %s / %d\n", - stack_info->profile_notified ? "Yes" : "No", - stack_info->hci_version); - btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, - &bt_patch_ver); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", - glcoex_ver_date_8723b_1ant, - glcoex_ver_8723b_1ant, fw_ver, - bt_patch_ver, bt_patch_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); - } + if (!btcoexist->auto_report_1ant) { + halbtc8723b1ant_query_bt_info(btcoexist); + halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); + } else { + halbtc8723b1ant_monitor_bt_ctr(btcoexist); + halbtc8723b1ant_monitor_wifi_ctr(btcoexist); -#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) - halbtc8723b1ant_query_bt_info(btcoexist); - halbtc8723b1ant_monitor_bt_ctr(btcoexist); - halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); -#else - if (btc8723b1ant_is_wifi_status_changed(btcoexist) || - coex_dm->auto_tdma_adjust) { - halbtc8723b1ant_run_coexist_mechanism(btcoexist); - } + if ((coex_sta->high_priority_tx + coex_sta->high_priority_rx < 50) && + bt_link_info->hid_exist) + bt_link_info->hid_exist = false; - coex_sta->special_pkt_period_cnt++; -#endif + if (btc8723b1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) { + halbtc8723b1ant_run_coexist_mechanism(btcoexist); + } + coex_sta->special_pkt_period_cnt++; + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 75f8094b7a34..8d4fde235e11 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -25,8 +25,6 @@ /********************************************************************** * The following is for 8723B 1ANT BT Co-exist definition **********************************************************************/ -#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1 - #define BT_INFO_8723B_1ANT_B_FTP BIT7 #define BT_INFO_8723B_1ANT_B_A2DP BIT6 #define BT_INFO_8723B_1ANT_B_HID BIT5 @@ -41,6 +39,8 @@ #define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 +#define BT_8723B_1ANT_WIFI_NOISY_THRESH 50 + enum _BT_INFO_SRC_8723B_1ANT { BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, @@ -84,13 +84,16 @@ enum _BT_8723B_1ANT_COEX_ALGO { }; struct coex_dm_8723b_1ant { + /* hw setting */ + u8 pre_ant_pos_type; + u8 cur_ant_pos_type; /* fw mechanism */ bool cur_ignore_wlan_act; bool pre_ignore_wlan_act; u8 pre_ps_tdma; u8 cur_ps_tdma; u8 ps_tdma_para[5]; - u8 tdma_adj_type; + u8 ps_tdma_du_adj_type; bool auto_tdma_adjust; bool pre_ps_tdma_on; bool cur_ps_tdma_on; @@ -133,16 +136,21 @@ struct coex_dm_8723b_1ant { u8 cur_retry_limit_type; u8 pre_ampdu_time_type; u8 cur_ampdu_time_type; + u32 arp_cnt; u8 error_condition; }; struct coex_sta_8723b_1ant { + bool bt_disabled; bool bt_link_exist; bool sco_exist; bool a2dp_exist; bool hid_exist; bool pan_exist; + bool bt_hi_pri_link_exist; + u8 num_of_profile; + bool bt_abnormal_scan; bool under_lps; bool under_ips; @@ -154,31 +162,63 @@ struct coex_sta_8723b_1ant { u8 bt_rssi; u8 pre_bt_rssi_state; u8 pre_wifi_rssi_state[4]; + bool bt_tx_rx_mask; bool c2h_bt_info_req_sent; u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX]; + bool bt_whck_test; bool c2h_bt_inquiry_page; + bool c2h_bt_remote_name_req; + bool wifi_is_high_pri_task; u8 bt_retry_cnt; u8 bt_info_ext; + u8 scan_ap_num; + bool cck_ever_lock; + u8 coex_table_type; + bool force_lps_on; + u32 pop_event_cnt; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_agg; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_agg; + + bool cck_lock; + bool pre_ccklock; + + u32 wrong_profile_notification; + + u8 a2dp_bit_pool; + u8 cut_version; }; /************************************************************************* * The following is interface which will notify coex module. *************************************************************************/ -void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length); -void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); -void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_power_on_setting(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only); +void ex_btc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_btc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8723b1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); +void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 2f3946be4ce2..31965f0ef69d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -707,6 +707,36 @@ static void btc8723b2ant_dec_bt_pwr(struct btc_coexist *btcoexist, coex_dm->pre_dec_bt_pwr_lvl = coex_dm->cur_dec_bt_pwr_lvl; } +static +void halbtc8723b2ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static +void btc8723b2ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, bool enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + static void btc8723b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, bool force_exec, u8 fw_dac_swing_lvl) { @@ -3666,6 +3696,7 @@ void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->auto_report_2ant = true; } void ex_btc8723b2ant_power_on_setting(struct btc_coexist *btcoexist) @@ -3966,9 +3997,8 @@ void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) - btc8723b2ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_2ant) + btc8723b2ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -4190,14 +4220,11 @@ void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, } else { /* BT already NOT ignore Wlan active, do nothing here.*/ } -#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) - if ((coex_sta->bt_info_ext & BIT4)) { - /* BT auto report already enabled, do nothing*/ - } else { - btc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC, - true); + if (!btcoexist->auto_report_2ant) { + if (!(coex_sta->bt_info_ext & BIT4)) + btc8723b2ant_bt_auto_report(btcoexist, + FORCE_EXEC, true); } -#endif } /* check BIT2 first ==> check if bt is under inquiry or page scan */ @@ -4347,21 +4374,22 @@ void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist) } } -#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) - btc8723b2ant_query_bt_info(btcoexist); -#else - btc8723b2ant_monitor_bt_ctr(btcoexist); - btc8723b2ant_monitor_wifi_ctr(btcoexist); + if (!btcoexist->auto_report_2ant) { + btc8723b2ant_query_bt_info(btcoexist); + } else { + btc8723b2ant_monitor_bt_ctr(btcoexist); + btc8723b2ant_monitor_wifi_ctr(btcoexist); - /* for some BT speakers that High-Priority pkts appear before - * playing, this will cause HID exist - */ - if ((coex_sta->high_priority_tx + coex_sta->high_priority_rx < 50) && - (bt_link_info->hid_exist)) - bt_link_info->hid_exist = false; - - if (btc8723b2ant_is_wifi_status_changed(btcoexist) || - coex_dm->auto_tdma_adjust) - btc8723b2ant_run_coexist_mechanism(btcoexist); -#endif + /* for some BT speakers that High-Priority pkts appear before + * playing, this will cause HID exist + */ + if ((coex_sta->high_priority_tx + + coex_sta->high_priority_rx < 50) && + (bt_link_info->hid_exist)) + bt_link_info->hid_exist = false; + + if (btc8723b2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + btc8723b2ant_run_coexist_mechanism(btcoexist); + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 18a35c7faba9..bc1e3042e271 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -28,8 +28,6 @@ /************************************************************************ * The following is for 8723B 2Ant BT Co-exist definition ************************************************************************/ -#define BT_AUTO_REPORT_ONLY_8723B_2ANT 1 - #define BT_INFO_8723B_2ANT_B_FTP BIT7 #define BT_INFO_8723B_2ANT_B_A2DP BIT6 #define BT_INFO_8723B_2ANT_B_HID BIT5 @@ -198,5 +196,8 @@ void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist); void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist); void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void ex_btc8723b2ant_pre_load_firmware(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_power_on_setting(struct btc_coexist *btcoexist); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 5e9f3b0f7a25..4efac5fe9982 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1107,8 +1107,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x3, 0x11, 0x10); break; case 6: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, - 0x3, 0x0, 0x0); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20, + 0x3, 0x11, 0x13); break; case 7: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc, @@ -1128,8 +1128,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0xa, 0x0, 0x40); break; case 11: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, - 0x03, 0x10, 0x10); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, + 0x03, 0x10, 0x50); rssi_adjust_val = 20; break; case 12: @@ -1137,8 +1137,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x0a, 0x0, 0x50); break; case 13: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x18, - 0x18, 0x0, 0x10); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x12, + 0x12, 0x0, 0x50); break; case 14: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1e, @@ -1163,8 +1163,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x03, 0x11, 0x10); break; case 21: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, - 0x03, 0x11, 0x10); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x11); break; case 22: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, @@ -1204,16 +1204,16 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x1a, 0x1, 0x10); break; case 30: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, - 0x3, 0x10, 0x50); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x30, + 0x3, 0x10, 0x10); break; case 31: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); break; case 32: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa, - 0x3, 0x10, 0x0); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35, + 0x3, 0x11, 0x11); break; case 33: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25, @@ -1231,6 +1231,28 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, btc8821a1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); break; + case 40: + /* SoftAP only with no sta associated, BT disable, TDMA + * mode for power saving + * + * here softap mode screen off will cost 70-80mA for + * phone + */ + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18, + 0x00, 0x10, 0x24); + break; + case 41: + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, + 0x3, 0x11, 0x11); + break; + case 42: + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x20, + 0x3, 0x11, 0x11); + break; + case 43: + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x30, + 0x3, 0x10, 0x11); + break; } } else { /* disable PS tdma */ @@ -1619,15 +1641,23 @@ static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, return; } else if (bt_link_info->a2dp_only) { /* A2DP */ - if ((bt_rssi_state != BTC_RSSI_STATE_HIGH) && - (bt_rssi_state != BTC_RSSI_STATE_STAY_HIGH)) { + if (wifi_status == BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else if ((bt_rssi_state != BTC_RSSI_STATE_HIGH) && + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { /* for low BT RSSI */ - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 11); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); coex_dm->auto_tdma_adjust = false; } - - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) { /* HID+A2DP */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || @@ -1638,7 +1668,7 @@ static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, } else { /*for low BT RSSI*/ btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 11); + true, 14); coex_dm->auto_tdma_adjust = false; } @@ -1647,13 +1677,13 @@ static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, (bt_link_info->hid_exist && bt_link_info->pan_exist)) { /* PAN(OPP, FTP), HID+PAN(OPP, FTP) */ btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); coex_dm->auto_tdma_adjust = false; } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || (bt_link_info->hid_exist && bt_link_info->a2dp_exist && bt_link_info->pan_exist)) { /* A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP) */ - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 43); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); coex_dm->auto_tdma_adjust = false; } else { @@ -1718,52 +1748,49 @@ void btc8821a1ant_action_wifi_connected_scan(struct btc_coexist *btcoexist) /* tdma and coex table */ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + if (bt_link_info->a2dp_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - } - } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == - coex_dm->bt_status) || - (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_SCO_BUSY) || + (coex_dm->bt_status == + BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY)) { btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } static void btc8821a1ant_act_wifi_conn_sp_pkt(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - bool hs_connecting = false; - - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); /* tdma and coex table */ - if (coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_ACL_BUSY) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 22); - btc8821a1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 20); - btc8821a1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } - } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } + + if ((bt_link_info->hid_exist) && (bt_link_info->a2dp_exist)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if (bt_link_info->pan_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } @@ -1773,6 +1800,7 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) bool wifi_busy = false; bool scan = false, link = false, roam = false; bool under_4way = false; + bool ap_enable = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], CoexForWifiConnect()===>\n"); @@ -1790,24 +1818,37 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); if (scan || link || roam) { - btc8821a1ant_action_wifi_connected_scan(btcoexist); + if (scan) + btc8821a1ant_action_wifi_connected_scan(btcoexist); + else + btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); return; } /* power save state*/ + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == - coex_dm->bt_status && !btcoexist->bt_link_info.hid_only) - btc8821a1ant_power_save_state(btcoexist, - BTC_PS_LPS_ON, 0x50, 0x4); - else + coex_dm->bt_status && !ap_enable && + !btcoexist->bt_link_info.hid_only) { + if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) + /* A2DP */ + btc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else + btc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, + 0x50, 0x4); + } else { btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } /* tdma and coex table */ - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); if (!wifi_busy) { if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist, @@ -1819,8 +1860,7 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 5); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } @@ -1835,7 +1875,7 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } @@ -1988,11 +2028,11 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, - 1, 1); + 0, 1); } else { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, - 1, 1); + 0, 1); } } else { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, @@ -2056,7 +2096,6 @@ static void btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) */ btc8821a1ant_sw_mechanism(btcoexist, false); - btc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); btc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); } @@ -2116,6 +2155,7 @@ static void btc8821a1ant_init_hw_config(struct btc_coexist *btcoexist, void ex_btc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist, bool wifionly) { btc8821a1ant_init_hw_config(btcoexist, true, wifionly); + btcoexist->auto_report_1ant = true; } void ex_btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) @@ -2406,9 +2446,8 @@ void ex_btc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1) - btc8821a1ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_1ant) + btc8821a1ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -2434,7 +2473,7 @@ void ex_btc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) btc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); /* set PTA control */ - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); } else if (BTC_IPS_LEAVE == type) { @@ -2442,7 +2481,9 @@ void ex_btc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], IPS LEAVE notify\n"); coex_sta->under_ips = false; - btc8821a1ant_run_coexist_mechanism(btcoexist); + btc8821a1ant_init_hw_config(btcoexist, false, false); + btc8821a1ant_init_coex_dm(btcoexist); + btc8821a1ant_query_bt_info(btcoexist); } } @@ -2484,6 +2525,19 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) return; } + if (type == BTC_SCAN_START) { + coex_sta->wifi_is_high_pri_task = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN START notify\n"); + + /* Force antenna setup for no scan result issue */ + btc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN FINISH notify\n"); + } + if (coex_sta->bt_disabled) return; @@ -2538,7 +2592,7 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; - bool wifi_connected = false, bt_hs_on = false; + bool wifi_connected = false, bt_hs_on = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; bool bt_ctrl_agg_buf_size = false; @@ -2556,6 +2610,18 @@ void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) return; } + if (type == BTC_ASSOCIATE_START) { + coex_sta->wifi_is_high_pri_task = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT START notify\n"); + coex_dm->arp_cnt = 0; + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT FINISH notify\n"); + coex_dm->arp_cnt = 0; + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status >> 16; @@ -2621,6 +2687,7 @@ void ex_btc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], MEDIA disconnect notify\n"); + coex_dm->arp_cnt = 0; } /* only 2.4G we need to inform bt the chnl mask */ @@ -2674,6 +2741,24 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, return; } + if (type == BTC_PACKET_DHCP || type == BTC_PACKET_EAPOL || + type == BTC_PACKET_ARP) { + coex_sta->wifi_is_high_pri_task = true; + + if (type == BTC_PACKET_ARP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet ARP notify\n"); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet DHCP or EAPOL notify\n"); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet [Type = %d] notify\n", + type); + } + coex_sta->special_pkt_period_cnt = 0; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, @@ -2696,8 +2781,20 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, return; } - if (BTC_PACKET_DHCP == type || - BTC_PACKET_EAPOL == type) { + if (type == BTC_PACKET_DHCP || type == BTC_PACKET_EAPOL || + type == BTC_PACKET_ARP) { + if (type == BTC_PACKET_ARP) { + coex_dm->arp_cnt++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + if (coex_dm->arp_cnt >= 10) + /* if APR PKT > 10 after connect, do not go to + * btc8821a1ant_act_wifi_conn_sp_pkt + */ + return; + } + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], special Packet(%d) notify\n", type); btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist); @@ -2742,14 +2839,28 @@ void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, } if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) { - coex_sta->bt_retry_cnt = /* [3:0]*/ - coex_sta->bt_info_c2h[rsp_source][2]&0xf; + /* [3:0] */ + coex_sta->bt_retry_cnt = + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; coex_sta->bt_rssi = - coex_sta->bt_info_c2h[rsp_source][3]*2+10; + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; - coex_sta->bt_info_ext = - coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + + coex_sta->bt_tx_rx_mask = + (coex_sta->bt_info_c2h[rsp_source][2] & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (!coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != + * 0x15 => Need to switch BT TRx Mask + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x15); + } /* Here we need to resend some wifi info to BT * because bt is reset and lost the info @@ -2831,11 +2942,11 @@ void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); } else if ((bt_info&BT_INFO_8821A_1ANT_B_SCO_ESCO) || - (bt_info&BT_INFO_8821A_1ANT_B_SCO_BUSY)) { + (bt_info & BT_INFO_8821A_1ANT_B_SCO_BUSY)) { coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); - } else if (bt_info&BT_INFO_8821A_1ANT_B_ACL_BUSY) { + } else if (bt_info & BT_INFO_8821A_1ANT_B_ACL_BUSY) { if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) coex_dm->auto_tdma_adjust = false; coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY; @@ -2964,10 +3075,10 @@ void ex_btc8821a1ant_periodical(struct btc_coexist *btcoexist) "[BTCoex], ****************************************************************\n"); } -#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) - btc8821a1ant_query_bt_info(btcoexist); - btc8821a1ant_monitor_bt_ctr(btcoexist); -#else - coex_sta->special_pkt_period_cnt++; -#endif + if (!btcoexist->auto_report_1ant) { + btc8821a1ant_query_bt_info(btcoexist); + btc8821a1ant_monitor_bt_ctr(btcoexist); + } else { + coex_sta->special_pkt_period_cnt++; + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h index 1bd1ebe3364e..b0a6626fbb66 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -27,8 +27,6 @@ * The following is for 8821A 1ANT BT Co-exist definition *=========================================== */ -#define BT_AUTO_REPORT_ONLY_8821A_1ANT 0 - #define BT_INFO_8821A_1ANT_B_FTP BIT7 #define BT_INFO_8821A_1ANT_B_A2DP BIT6 #define BT_INFO_8821A_1ANT_B_HID BIT5 @@ -135,6 +133,7 @@ struct coex_dm_8821a_1ant { u8 cur_retry_limit_type; u8 pre_ampdu_time_type; u8 cur_ampdu_time_type; + u32 arp_cnt; u8 error_condition; }; @@ -155,6 +154,7 @@ struct coex_sta_8821a_1ant { u32 low_priority_tx; u32 low_priority_rx; u8 bt_rssi; + bool bt_tx_rx_mask; u8 pre_bt_rssi_state; u8 pre_wifi_rssi_state[4]; bool c2h_bt_info_req_sent; @@ -170,21 +170,23 @@ struct coex_sta_8821a_1ant { * The following is interface which will notify coex module. *=========================================== */ -void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length); -void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); -void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, - u8 op_len, u8 *data); +void ex_btc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only); +void ex_btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_btc8821a1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); +void ex_btc8821a1ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, + u8 op_len, u8 *data); +void ex_btc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 841b4a83ab70..41943c34edff 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3220,12 +3220,16 @@ static void btc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) /* HID+A2DP+PAN(EDR) */ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; - bt_info_ext = coex_sta->bt_info_ext; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); @@ -3235,44 +3239,32 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) else btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - if (wifi_bw == BTC_WIFI_BW_LEGACY) { - /* for HID at 11b/g mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5a5a5a5a, 0xffff, 0x3); + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (wifi_bw == BTC_WIFI_BW_HT40) + btc8821a2ant_tdma_duration_adjust(btcoexist, true, + true, 3); + else + btc8821a2ant_tdma_duration_adjust(btcoexist, true, + false, 3); } else { - /* for HID quality & wifi performance balance at 11n mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5a5a5a5a, 0xffff, 0x3); + btc8821a2ant_tdma_duration_adjust(btcoexist, true, true, 3); } - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } - } else { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } - } - - /* sw mechanism */ + /* sw mechanism */ + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, true, @@ -3286,33 +3278,6 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, false, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, false, 3); - } - } else { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 3); - } - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, true, @@ -3330,19 +3295,46 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; u32 wifi_bw; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; - bt_info_ext = coex_sta->bt_info_ext; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 3, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 37); - if (BTC_RSSI_HIGH(bt_rssi_state)) - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); - else - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x5); + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_LEGACY) { + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } else { + /* only 802.11N mode we have to dec bt power to 4 degree */ + if (BTC_RSSI_HIGH(bt_rssi_state)) { + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + if (ap_num < 10) + btc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 4); + else + btc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 2); + } else if (BTC_RSSI_MEDIUM(bt_rssi_state)) { + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + } else { + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } + } if (wifi_bw == BTC_WIFI_BW_LEGACY) { btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); @@ -3354,36 +3346,15 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) 0x4); } - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext & BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } else { - if (bt_info_ext & BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } else { + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } - /* sw mechanism */ + /* sw mechanism */ + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, true, @@ -3397,36 +3368,6 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext & BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } else { - if (bt_info_ext & BIT0) { - /*a2dp basic rate*/ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } else { - /*a2dp edr rate*/ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, true, @@ -3544,14 +3485,14 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) if (btc8821a2ant_is_common_action(btcoexist)) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Action 2-Ant common\n"); - coex_dm->reset_tdma_adjust = true; + coex_dm->auto_tdma_adjust = true; } else { if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], pre_algorithm = %d, cur_algorithm = %d\n", coex_dm->pre_algorithm, coex_dm->cur_algorithm); - coex_dm->reset_tdma_adjust = true; + coex_dm->auto_tdma_adjust = false; } switch (coex_dm->cur_algorithm) { case BT_8821A_2ANT_COEX_ALGO_SCO: @@ -3614,6 +3555,26 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } +static void btc8821a2ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[2] = {0}; + u32 fw_ver = 0; + + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* WiFi goto standby while GNT_BT 0-->1 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, h2c_parameter); + } else { + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } +} + /************************************************************** * extern function start with ex_btc8821a2ant_ **************************************************************/ @@ -3637,6 +3598,7 @@ void ex_btc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) /* Antenna config */ btc8821a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, true, false); + coex_sta->dis_ver_info_cnt = 0; /* PTA parameter */ btc8821a2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); @@ -3648,6 +3610,43 @@ void ex_btc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); } +void ex_btc8821a2ant_pre_load_firmware(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /** + * S0 or S1 setting and Local register setting(By the setting fw can get + * ant number, S0/S1, ... info) + * + * Local setting bit define + * BIT0: "0" for no antenna inverse; "1" for antenna inverse + * BIT1: "0" for internal switch; "1" for external switch + * BIT2: "0" for one antenna; "1" for two antenna + * NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and + * BIT2=0 + */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + void ex_btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -3748,14 +3747,6 @@ void ex_btc8821a2ant_display_coex_info(struct btc_coexist *btcoexist) ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", - ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : - ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) - ? "idle" : ((BT_8821A_2ANT_BT_STATUS_CON_IDLE == - coex_dm->bt_status) ? "connected-idle" : "busy"))), - coex_sta->bt_rssi, coex_sta->bt_retry_cnt); - if (stack_info->profile_notified) { RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", @@ -3791,11 +3782,6 @@ void ex_btc8821a2ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "\r\n %-35s = %d/ %d/ %d/ %d ", - "SM1[ShRf/ LpRA/ LimDig/ btLna]", - coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, - coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, @@ -3900,11 +3886,16 @@ void ex_btc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], IPS ENTER notify\n"); coex_sta->under_ips = true; + btc8821a2ant_wifi_off_hw_cfg(btcoexist); + btc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); btc8821a2ant_coex_all_off(btcoexist); } else if (BTC_IPS_LEAVE == type) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], IPS LEAVE notify\n"); coex_sta->under_ips = false; + ex_btc8821a2ant_init_hwconfig(btcoexist); + btc8821a2ant_init_coex_dm(btcoexist); + btc8821a2ant_query_bt_info(btcoexist); } } @@ -4016,9 +4007,12 @@ void ex_btc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, u8 bt_info = 0; u8 i, rsp_source = 0; bool bt_busy = false, limited_dig = false; - bool wifi_connected = false, bt_hs_on = false; + bool wifi_connected = false, wifi_under_5g = false; coex_sta->c2h_bt_info_req_sent = false; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); rsp_source = tmp_buf[0] & 0xf; if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX) @@ -4041,16 +4035,35 @@ void ex_btc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, } } + if (btcoexist->manual_control) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n"); + return; + } + if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) { /* [3:0] */ coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2]&0xf; coex_sta->bt_rssi = - coex_sta->bt_info_c2h[rsp_source][3]*2+10; + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; - coex_sta->bt_info_ext = - coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + + coex_sta->bt_tx_rx_mask = + (coex_sta->bt_info_c2h[rsp_source][2] & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != + * 0x01 => Need to switch BT TRx Mask + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x01\n"); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x01); + } /* Here we need to resend some wifi info to BT * because bt is reset and loss of the info @@ -4068,70 +4081,121 @@ void ex_btc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, } - if ((coex_sta->bt_info_ext & BIT3)) { - btc8821a2ant_ignore_wlan_act(btcoexist, - FORCE_EXEC, false); - } else { - /* BT already NOT ignore Wlan active, do nothing here.*/ + if (!btcoexist->manual_control && !wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info = 0x%x!!\n", + coex_sta->bt_info_ext); + if ((coex_sta->bt_info_ext & BIT(3))) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit3=1, wifi_connected=%d\n", + wifi_connected); + if (wifi_connected) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + btc8821a2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, + false); + } + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit3=0, wifi_connected=%d\n", + wifi_connected); + /* BT already NOT ignore Wlan active, do nothing + * here. + */ + if (!wifi_connected) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT ext info bit3 check, set BT to ignore Wlan active!!\n"); + btc8821a2ant_ignore_wlan_act( + btcoexist, FORCE_EXEC, true); + } + } } } - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); /* check BIT2 first ==> check if bt is under inquiry or page scan*/ if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) { coex_sta->c2h_bt_inquiry_page = true; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; } else { coex_sta->c2h_bt_inquiry_page = false; - if (bt_info == 0x1) { - /* connection exists but not busy*/ - coex_sta->bt_link_exist = true; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE; - } else if (bt_info & BT_INFO_8821A_2ANT_B_CONNECTION) { - /* connection exists and some link is busy*/ - coex_sta->bt_link_exist = true; - if (bt_info & BT_INFO_8821A_2ANT_B_FTP) - coex_sta->pan_exist = true; - else - coex_sta->pan_exist = false; - if (bt_info & BT_INFO_8821A_2ANT_B_A2DP) - coex_sta->a2dp_exist = true; - else - coex_sta->a2dp_exist = false; - if (bt_info & BT_INFO_8821A_2ANT_B_HID) - coex_sta->hid_exist = true; - else - coex_sta->hid_exist = false; - if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) - coex_sta->sco_exist = true; - else - coex_sta->sco_exist = false; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; - } else { - coex_sta->bt_link_exist = false; + } + /* set link exist status */ + if (!(bt_info & BT_INFO_8821A_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8821A_2ANT_B_FTP) + coex_sta->pan_exist = true; + else coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_HID) + coex_sta->hid_exist = true; + else coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else coex_sta->sco_exist = false; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE; + + if ((!coex_sta->hid_exist) && + (!coex_sta->c2h_bt_inquiry_page) && + (!coex_sta->sco_exist)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= 160) + coex_sta->hid_exist = true; } + } - btc8821a2ant_update_bt_link_info(btcoexist); + btc8821a2ant_update_bt_link_info(btcoexist); + + if (!(bt_info & BT_INFO_8821A_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (bt_info == BT_INFO_8821A_2ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8821A_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_SCO_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (bt_info & BT_INFO_8821A_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_ACL_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_MAX; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); } - if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status) + if ((coex_dm->bt_status == BT_8821A_2ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8821A_2ANT_BT_STATUS_SCO_BUSY) || + (coex_dm->bt_status == BT_8821A_2ANT_BT_STATUS_ACL_SCO_BUSY)) { bt_busy = true; - else + limited_dig = true; + } else { bt_busy = false; + limited_dig = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); - if (BT_8821A_2ANT_BT_STATUS_IDLE != coex_dm->bt_status) - limited_dig = true; - else - limited_dig = false; coex_dm->limited_dig = limited_dig; - btcoexist->btc_set(btcoexist, - BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); btc8821a2ant_run_coexist_mechanism(btcoexist); } @@ -4143,46 +4207,57 @@ void ex_btc8821a2ant_halt_notify(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Halt notify\n"); + btc8821a2ant_wifi_off_hw_cfg(btcoexist); btc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); ex_btc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); } +void ex_btc8821a2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify\n"); + + if (pnp_state == BTC_WIFI_PNP_SLEEP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to SLEEP\n"); + } else if (pnp_state == BTC_WIFI_PNP_WAKE_UP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to WAKE UP\n"); + ex_btc8821a2ant_init_hwconfig(btcoexist); + btc8821a2ant_init_coex_dm(btcoexist); + btc8821a2ant_query_bt_info(btcoexist); + } +} + void ex_btc8821a2ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - static u8 dis_ver_info_cnt; - struct btc_board_info *board_info = &btcoexist->board_info; - struct btc_stack_info *stack_info = &btcoexist->stack_info; - u32 fw_ver = 0, bt_patch_ver = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], ==========================Periodical===========================\n"); - if (dis_ver_info_cnt <= 5) { - dis_ver_info_cnt += 1; - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", - board_info->pg_ant_num, - board_info->btdm_ant_num, - board_info->btdm_ant_pos); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], BT stack/ hci ext ver = %s / %d\n", - stack_info->profile_notified ? "Yes" : "No", - stack_info->hci_version); - btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, - &bt_patch_ver); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", - glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant, - fw_ver, bt_patch_ver, bt_patch_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); + if (coex_sta->dis_ver_info_cnt <= 5) { + coex_sta->dis_ver_info_cnt += 1; + if (coex_sta->dis_ver_info_cnt == 3) { + /* Antenna config to set 0x765 = 0x0 (GNT_BT control by + * PTA) after initial + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Set GNT_BT control by PTA\n"); + btc8821a2ant_set_ant_path(btcoexist, + BTC_ANT_WIFI_AT_MAIN, false, false); + } } - btc8821a2ant_query_bt_info(btcoexist); - btc8821a2ant_monitor_bt_ctr(btcoexist); - btc8821a2ant_monitor_wifi_ctr(btcoexist); + if (btcoexist->auto_report_2ant) { + btc8821a2ant_query_bt_info(btcoexist); + } else { + btc8821a2ant_monitor_bt_ctr(btcoexist); + btc8821a2ant_monitor_wifi_ctr(btcoexist); + + if (btc8821a2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + btc8821a2ant_run_coexist_mechanism(btcoexist); + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index 535ca10e910b..a839d5574422 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -54,6 +54,9 @@ enum _BT_8821A_2ANT_BT_STATUS { BT_8821A_2ANT_BT_STATUS_IDLE = 0x0, BT_8821A_2ANT_BT_STATUS_CON_IDLE = 0x1, BT_8821A_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8821A_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821A_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821A_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, BT_8821A_2ANT_BT_STATUS_MAX }; @@ -76,10 +79,6 @@ struct coex_dm_8821a_2ant { /* fw mechanism */ bool pre_dec_bt_pwr_lvl; bool cur_dec_bt_pwr_lvl; - bool pre_bt_lna_constrain; - bool cur_bt_lna_constrain; - u8 pre_bt_psd_mode; - u8 cur_bt_psd_mode; u8 pre_fw_dac_swing_lvl; u8 cur_fw_dac_swing_lvl; bool cur_ignore_wlan_act; @@ -143,6 +142,7 @@ struct coex_sta_8821a_2ant { u32 low_priority_tx; u32 low_priority_rx; u8 bt_rssi; + bool bt_tx_rx_mask; u8 pre_bt_rssi_state; u8 pre_wifi_rssi_state[4]; bool c2h_bt_info_req_sent; @@ -164,6 +164,8 @@ struct coex_sta_8821a_2ant { u8 coex_table_type; bool force_lps_on; + + u8 dis_ver_info_cnt; }; /*=========================================== @@ -171,58 +173,60 @@ struct coex_sta_8821a_2ant { *=========================================== */ void -ex_halbtc8821a2ant_init_hwconfig( +ex_btc8821a2ant_init_hwconfig( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_init_coex_dm( +ex_btc8821a2ant_init_coex_dm( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_ips_notify( +ex_btc8821a2ant_ips_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_lps_notify( +ex_btc8821a2ant_lps_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_scan_notify( +ex_btc8821a2ant_scan_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_connect_notify( +ex_btc8821a2ant_connect_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_media_status_notify( +ex_btc8821a2ant_media_status_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_special_packet_notify( +ex_btc8821a2ant_special_packet_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_bt_info_notify( +ex_btc8821a2ant_bt_info_notify( struct btc_coexist *btcoexist, u8 *tmp_buf, u8 length ); void -ex_halbtc8821a2ant_halt_notify( +ex_btc8821a2ant_halt_notify( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_periodical( +ex_btc8821a2ant_periodical( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_display_coex_info( +ex_btc8821a2ant_display_coex_info( struct btc_coexist *btcoexist ); +void ex_btc8821a2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void ex_btc8821a2ant_pre_load_firmware(struct btc_coexist *btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index f13000612913..e6024b013ca5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -36,6 +36,20 @@ u32 btc_dbg_type[BTC_MSG_MAX]; /*************************************************** * Debug related function ***************************************************/ + +const char *const gl_btc_wifi_bw_string[] = { + "11bg", + "HT20", + "HT40", + "HT80", + "HT160" +}; + +const char *const gl_btc_wifi_freq_string[] = { + "2.4G", + "5G" +}; + static bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist) { if (!btcoexist->binded || NULL == btcoexist->adapter) @@ -54,28 +68,39 @@ static bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv) static void halbtc_dbg_init(void) { - u8 i; - - for (i = 0; i < BTC_MSG_MAX; i++) - btc_dbg_type[i] = 0; - - btc_dbg_type[BTC_MSG_INTERFACE] = -/* INTF_INIT | */ -/* INTF_NOTIFY | */ - 0; +} - btc_dbg_type[BTC_MSG_ALGORITHM] = -/* ALGO_BT_RSSI_STATE | */ -/* ALGO_WIFI_RSSI_STATE | */ -/* ALGO_BT_MONITOR | */ -/* ALGO_TRACE | */ -/* ALGO_TRACE_FW | */ -/* ALGO_TRACE_FW_DETAIL | */ -/* ALGO_TRACE_FW_EXEC | */ -/* ALGO_TRACE_SW | */ -/* ALGO_TRACE_SW_DETAIL | */ -/* ALGO_TRACE_SW_EXEC | */ - 0; +/*************************************************** + * helper function + ***************************************************/ +static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_sta_info *drv_priv; + u8 cnt = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT || + mac->opmode == NL80211_IFTYPE_AP) { + if (in_interrupt() > 0) { + list_for_each_entry(drv_priv, &rtlpriv->entry_list, + list) { + cnt++; + } + } else { + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_for_each_entry(drv_priv, &rtlpriv->entry_list, + list) { + cnt++; + } + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + } + } + if (cnt > 0) + return true; + else + return false; } static bool halbtc_is_bt40(struct rtl_priv *adapter) @@ -188,12 +213,14 @@ static void halbtc_leave_lps(struct btc_coexist *btcoexist) &ap_enable); if (ap_enable) { - pr_info("halbtc_leave_lps()<--dont leave lps under AP mode\n"); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "%s()<--dont leave lps under AP mode\n", __func__); return; } btcoexist->bt_info.bt_ctrl_lps = true; btcoexist->bt_info.bt_lps_on = false; + rtl_lps_leave(rtlpriv->mac80211.hw); } static void halbtc_enter_lps(struct btc_coexist *btcoexist) @@ -209,36 +236,93 @@ static void halbtc_enter_lps(struct btc_coexist *btcoexist) &ap_enable); if (ap_enable) { - pr_info("halbtc_enter_lps()<--dont enter lps under AP mode\n"); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "%s()<--dont enter lps under AP mode\n", __func__); return; } btcoexist->bt_info.bt_ctrl_lps = true; - btcoexist->bt_info.bt_lps_on = false; + btcoexist->bt_info.bt_lps_on = true; + rtl_lps_enter(rtlpriv->mac80211.hw); } static void halbtc_normal_lps(struct btc_coexist *btcoexist) { + struct rtl_priv *rtlpriv; + + rtlpriv = btcoexist->adapter; + if (btcoexist->bt_info.bt_ctrl_lps) { btcoexist->bt_info.bt_lps_on = false; + rtl_lps_leave(rtlpriv->mac80211.hw); btcoexist->bt_info.bt_ctrl_lps = false; } } -static void halbtc_leave_low_power(void) +static void halbtc_leave_low_power(struct btc_coexist *btcoexist) { } -static void halbtc_nomal_low_power(void) +static void halbtc_normal_low_power(struct btc_coexist *btcoexist) { } -static void halbtc_disable_low_power(void) +static void halbtc_disable_low_power(struct btc_coexist *btcoexist, + bool low_pwr_disable) { + /* TODO: original/leave 32k low power */ + btcoexist->bt_info.bt_disable_low_pwr = low_pwr_disable; } -static void halbtc_aggregation_check(void) +static void halbtc_aggregation_check(struct btc_coexist *btcoexist) { + bool need_to_act = false; + static unsigned long pre_time; + unsigned long cur_time = 0; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + /* To void continuous deleteBA=>addBA=>deleteBA=>addBA + * This function is not allowed to continuous called + * It can only be called after 8 seconds + */ + + cur_time = jiffies; + if (jiffies_to_msecs(cur_time - pre_time) <= 8000) { + /* over 8 seconds you can execute this function again. */ + return; + } + pre_time = cur_time; + + if (btcoexist->bt_info.reject_agg_pkt) { + need_to_act = true; + btcoexist->bt_info.pre_reject_agg_pkt = + btcoexist->bt_info.reject_agg_pkt; + } else { + if (btcoexist->bt_info.pre_reject_agg_pkt) { + need_to_act = true; + btcoexist->bt_info.pre_reject_agg_pkt = + btcoexist->bt_info.reject_agg_pkt; + } + + if (btcoexist->bt_info.pre_bt_ctrl_agg_buf_size != + btcoexist->bt_info.bt_ctrl_agg_buf_size) { + need_to_act = true; + btcoexist->bt_info.pre_bt_ctrl_agg_buf_size = + btcoexist->bt_info.bt_ctrl_agg_buf_size; + } + + if (btcoexist->bt_info.bt_ctrl_agg_buf_size) { + if (btcoexist->bt_info.pre_agg_buf_size != + btcoexist->bt_info.agg_buf_size) { + need_to_act = true; + } + btcoexist->bt_info.pre_agg_buf_size = + btcoexist->bt_info.agg_buf_size; + } + + if (need_to_act) + rtl_rx_ampdu_apply(rtlpriv); + } } static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) @@ -246,10 +330,37 @@ static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) return 0; } -static s32 halbtc_get_wifi_rssi(struct rtl_priv *adapter) +u32 halbtc_get_wifi_link_status(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = adapter; - s32 undec_sm_pwdb = 0; + /* return value: + * [31:16] => connected port number + * [15:0] => port connected bit define + */ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + u32 ret_val = 0; + u32 port_connected_status = 0, num_of_connected_port = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->link_state >= MAC80211_LINKED) { + port_connected_status |= WIFI_STA_CONNECTED; + num_of_connected_port++; + } + /* AP & ADHOC & MESH */ + if (is_any_client_connect_to_ap(btcoexist)) { + port_connected_status |= WIFI_AP_CONNECTED; + num_of_connected_port++; + } + /* TODO: P2P Connected Status */ + + ret_val = (num_of_connected_port << 16) | port_connected_status; + + return ret_val; +} + +static s32 halbtc_get_wifi_rssi(struct rtl_priv *rtlpriv) +{ + int undec_sm_pwdb = 0; if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; @@ -270,6 +381,7 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) u32 *u32_tmp = (u32 *)out_buf; u8 *u8_tmp = (u8 *)out_buf; bool tmp = false; + bool ret = true; if (!halbtc_is_bt_coexist_available(btcoexist)) return false; @@ -277,12 +389,17 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) switch (get_type) { case BTC_GET_BL_HS_OPERATION: *bool_tmp = false; + ret = false; break; case BTC_GET_BL_HS_CONNECTING: *bool_tmp = false; + ret = false; break; case BTC_GET_BL_WIFI_CONNECTED: - if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && + rtlpriv->mac80211.link_state >= MAC80211_LINKED) + tmp = true; + if (is_any_client_connect_to_ap(btcoexist)) tmp = true; *bool_tmp = tmp; break; @@ -304,32 +421,26 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) else *bool_tmp = false; break; - case BTC_GET_BL_WIFI_ROAM: /*TODO*/ + case BTC_GET_BL_WIFI_ROAM: if (mac->link_state == MAC80211_LINKING) *bool_tmp = true; else *bool_tmp = false; break; - case BTC_GET_BL_WIFI_4_WAY_PROGRESS: /*TODO*/ - *bool_tmp = false; - + case BTC_GET_BL_WIFI_4_WAY_PROGRESS: + *bool_tmp = rtlpriv->btcoexist.btc_info.in_4way; break; case BTC_GET_BL_WIFI_UNDER_5G: - *bool_tmp = false; /*TODO*/ - - case BTC_GET_BL_WIFI_DHCP: /*TODO*/ - break; - case BTC_GET_BL_WIFI_SOFTAP_IDLE: - *bool_tmp = true; - break; - case BTC_GET_BL_WIFI_SOFTAP_LINKING: - *bool_tmp = false; - break; - case BTC_GET_BL_WIFI_IN_EARLY_SUSPEND: - *bool_tmp = false; + if (rtlhal->current_bandtype == BAND_ON_5G) + *bool_tmp = true; + else + *bool_tmp = false; break; case BTC_GET_BL_WIFI_AP_MODE_ENABLE: - *bool_tmp = false; + if (mac->opmode == NL80211_IFTYPE_AP) + *bool_tmp = true; + else + *bool_tmp = false; break; case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: if (NO_ENCRYPTION == rtlpriv->sec.pairwise_enc_algorithm) @@ -338,16 +449,26 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *bool_tmp = true; break; case BTC_GET_BL_WIFI_UNDER_B_MODE: - *bool_tmp = false; /*TODO*/ + if (rtlpriv->mac80211.mode == WIRELESS_MODE_B) + *bool_tmp = true; + else + *bool_tmp = false; break; case BTC_GET_BL_EXT_SWITCH: *bool_tmp = false; break; + case BTC_GET_BL_WIFI_IS_IN_MP_MODE: + *bool_tmp = false; + break; + case BTC_GET_BL_IS_ASUS_8723B: + *bool_tmp = false; + break; case BTC_GET_S4_WIFI_RSSI: *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); break; - case BTC_GET_S4_HS_RSSI: /*TODO*/ - *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); + case BTC_GET_S4_HS_RSSI: + *s32_tmp = 0; + ret = false; break; case BTC_GET_U4_WIFI_BW: *u32_tmp = halbtc_get_wifi_bw(btcoexist); @@ -359,7 +480,10 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *u32_tmp = BTC_WIFI_TRAFFIC_RX; break; case BTC_GET_U4_WIFI_FW_VER: - *u32_tmp = rtlhal->fw_version; + *u32_tmp = (rtlhal->fw_version << 16) | rtlhal->fw_subversion; + break; + case BTC_GET_U4_WIFI_LINK_STATUS: + *u32_tmp = halbtc_get_wifi_link_status(btcoexist); break; case BTC_GET_U4_BT_PATCH_VER: *u32_tmp = halbtc_get_bt_patch_version(btcoexist); @@ -374,10 +498,17 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist); break; case BTC_GET_U1_WIFI_HS_CHNL: - *u8_tmp = 1;/*BT_OperateChnl(rtlpriv);*/ + *u8_tmp = 0; + ret = false; break; - case BTC_GET_U1_MAC_PHY_MODE: - *u8_tmp = BTC_MP_UNKNOWN; + case BTC_GET_U1_AP_NUM: + *u8_tmp = rtlpriv->btcoexist.btc_info.ap_num; + break; + case BTC_GET_U1_ANT_TYPE: + *u8_tmp = (u8)BTC_ANT_TYPE_0; + break; + case BTC_GET_U1_IOT_PEER: + *u8_tmp = 0; break; /************* 1Ant **************/ @@ -386,10 +517,11 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) break; default: + ret = false; break; } - return true; + return ret; } static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) @@ -398,6 +530,7 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) bool *bool_tmp = (bool *)in_buf; u8 *u8_tmp = (u8 *)in_buf; u32 *u32_tmp = (u32 *)in_buf; + bool ret = true; if (!halbtc_is_bt_coexist_available(btcoexist)) return false; @@ -420,11 +553,17 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) btcoexist->bt_info.reject_agg_pkt = *bool_tmp; break; case BTC_SET_BL_BT_CTRL_AGG_SIZE: - btcoexist->bt_info.bt_ctrl_buf_size = *bool_tmp; + btcoexist->bt_info.bt_ctrl_agg_buf_size = *bool_tmp; break; case BTC_SET_BL_INC_SCAN_DEV_NUM: btcoexist->bt_info.increase_scan_dev_num = *bool_tmp; break; + case BTC_SET_BL_BT_TX_RX_MASK: + btcoexist->bt_info.bt_tx_rx_mask = *bool_tmp; + break; + case BTC_SET_BL_MIRACAST_PLUS_BT: + btcoexist->bt_info.miracast_plus_bt = *bool_tmp; + break; /* set some u1Byte type variables. */ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp; @@ -432,25 +571,25 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) case BTC_SET_U1_AGG_BUF_SIZE: btcoexist->bt_info.agg_buf_size = *u8_tmp; break; - /* the following are some action which will be triggered */ + + /* the following are some action which will be triggered */ case BTC_SET_ACT_GET_BT_RSSI: - /*BTHCI_SendGetBtRssiEvent(rtlpriv);*/ + ret = false; break; case BTC_SET_ACT_AGGREGATE_CTRL: - halbtc_aggregation_check(); + halbtc_aggregation_check(btcoexist); break; - /* 1Ant */ + /* 1Ant */ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp; break; case BTC_SET_UI_SCAN_SIG_COMPENSATION: - /* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */ break; - case BTC_SET_U1_1ANT_LPS: + case BTC_SET_U1_LPS_VAL: btcoexist->bt_info.lps_val = *u8_tmp; break; - case BTC_SET_U1_1ANT_RPWM: + case BTC_SET_U1_RPWM_VAL: btcoexist->bt_info.rpwm_val = *u8_tmp; break; /* the following are some action which will be triggered */ @@ -464,41 +603,24 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) halbtc_normal_lps(btcoexist); break; case BTC_SET_ACT_DISABLE_LOW_POWER: - halbtc_disable_low_power(); + halbtc_disable_low_power(btcoexist, *bool_tmp); break; case BTC_SET_ACT_UPDATE_RAMASK: btcoexist->bt_info.ra_mask = *u32_tmp; break; case BTC_SET_ACT_SEND_MIMO_PS: break; - case BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT: - btcoexist->bt_info.force_exec_pwr_cmd_cnt++; - break; case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/ break; case BTC_SET_ACT_CTRL_BT_COEX: break; + case BTC_SET_ACT_CTRL_8723B_ANT: + break; default: break; } - return true; -} - -static void halbtc_display_coex_statistics(struct btc_coexist *btcoexist) -{ -} - -static void halbtc_display_bt_link_info(struct btc_coexist *btcoexist) -{ -} - -static void halbtc_display_bt_fw_info(struct btc_coexist *btcoexist) -{ -} - -static void halbtc_display_fw_pwr_mode_cmd(struct btc_coexist *btcoexist) -{ + return ret; } /************************************************************ @@ -574,6 +696,35 @@ static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data) rtl_write_dword(rtlpriv, reg_addr, data); } +void halbtc_write_local_reg_1byte(void *btc_context, u32 reg_addr, u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (btcoexist->chip_interface == BTC_INTF_SDIO) + ; + else if (btcoexist->chip_interface == BTC_INTF_PCI) + rtl_write_byte(rtlpriv, reg_addr, data); + else if (btcoexist->chip_interface == BTC_INTF_USB) + rtl_write_byte(rtlpriv, reg_addr, data); +} + +void halbtc_set_macreg(void *btc_context, u32 reg_addr, u32 bit_mask, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data); +} + +u32 halbtc_get_macreg(void *btc_context, u32 reg_addr, u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask); +} + static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask, u32 data) { @@ -619,50 +770,64 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, cmd_len, cmd_buf); } -static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type) +void halbtc_set_bt_reg(void *btc_context, u8 reg_type, u32 offset, u32 set_val) { - struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; - switch (disp_type) { - case BTC_DBG_DISP_COEX_STATISTICS: - halbtc_display_coex_statistics(btcoexist); - break; - case BTC_DBG_DISP_BT_LINK_INFO: - halbtc_display_bt_link_info(btcoexist); - break; - case BTC_DBG_DISP_BT_FW_VER: - halbtc_display_bt_fw_info(btcoexist); - break; - case BTC_DBG_DISP_FW_PWR_MODE_CMD: - halbtc_display_fw_pwr_mode_cmd(btcoexist); - break; - default: - break; + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 cmd_buffer1[4] = {0}; + u8 cmd_buffer2[4] = {0}; + u8 *addr_to_set = (u8 *)&offset; + u8 *value_to_set = (u8 *)&set_val; + u8 oper_ver = 0; + u8 req_num = 0; + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + cmd_buffer1[0] |= (oper_ver & 0x0f); /* Set OperVer */ + cmd_buffer1[0] |= ((req_num << 4) & 0xf0); /* Set ReqNum */ + cmd_buffer1[1] = 0x0d; /* OpCode: BT_LO_OP_WRITE_REG_VALUE */ + cmd_buffer1[2] = value_to_set[0]; /* Set WriteRegValue */ + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, 0x67, 4, + &cmd_buffer1[0]); + + msleep(200); + req_num++; + + cmd_buffer2[0] |= (oper_ver & 0x0f); /* Set OperVer */ + cmd_buffer2[0] |= ((req_num << 4) & 0xf0); /* Set ReqNum */ + cmd_buffer2[1] = 0x0c; /* OpCode: BT_LO_OP_WRITE_REG_ADDR */ + cmd_buffer2[3] = addr_to_set[0]; /* Set WriteRegAddr */ + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, 0x67, 4, + &cmd_buffer2[0]); } } +bool halbtc_under_ips(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + enum rf_pwrstate rtstate; + + if (ppsc->inactiveps) { + rtstate = ppsc->rfpwr_state; + + if (rtstate != ERFON && + ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { + return true; + } + } + + return false; +} + /***************************************************************** * Extern functions called by other module *****************************************************************/ -bool exhalbtc_initlize_variables(struct rtl_priv *adapter) +bool exhalbtc_initlize_variables(void) { struct btc_coexist *btcoexist = &gl_bt_coexist; - btcoexist->statistics.cnt_bind++; - halbtc_dbg_init(); - if (btcoexist->binded) - return false; - else - btcoexist->binded = true; - - btcoexist->chip_interface = BTC_INTF_UNKNOWN; - - if (NULL == btcoexist->adapter) - btcoexist->adapter = adapter; - - btcoexist->stack_info.profile_notified = false; - btcoexist->btc_read_1byte = halbtc_read_1byte; btcoexist->btc_write_1byte = halbtc_write_1byte; btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte; @@ -670,6 +835,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->btc_write_2byte = halbtc_write_2byte; btcoexist->btc_read_4byte = halbtc_read_4byte; btcoexist->btc_write_4byte = halbtc_write_4byte; + btcoexist->btc_write_local_reg_1byte = halbtc_write_local_reg_1byte; btcoexist->btc_set_bb_reg = halbtc_set_bbreg; btcoexist->btc_get_bb_reg = halbtc_get_bbreg; @@ -678,10 +844,11 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->btc_get_rf_reg = halbtc_get_rfreg; btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd; - btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg; btcoexist->btc_get = halbtc_get; btcoexist->btc_set = halbtc_set; + btcoexist->btc_set_bt_reg = halbtc_set_bt_reg; + btcoexist->bt_info.bt_ctrl_buf_size = false; btcoexist->bt_info.agg_buf_size = 5; @@ -690,40 +857,148 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) return true; } -void exhalbtc_init_hw_config(struct btc_coexist *btcoexist) +bool exhalbtc_bind_bt_coex_withadapter(void *adapter) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct btc_coexist *btcoexist = &gl_bt_coexist; + struct rtl_priv *rtlpriv = adapter; + u8 ant_num = 2, chip_type, single_ant_path = 0; + + if (btcoexist->binded) + return false; + + switch (rtlpriv->rtlhal.interface) { + case INTF_PCI: + btcoexist->chip_interface = BTC_INTF_PCI; + break; + case INTF_USB: + btcoexist->chip_interface = BTC_INTF_USB; + break; + default: + btcoexist->chip_interface = BTC_INTF_UNKNOWN; + break; + } + + btcoexist->binded = true; + btcoexist->statistics.cnt_bind++; + + btcoexist->adapter = adapter; + + btcoexist->stack_info.profile_notified = false; + + btcoexist->bt_info.bt_ctrl_agg_buf_size = false; + btcoexist->bt_info.agg_buf_size = 5; + + btcoexist->bt_info.increase_scan_dev_num = false; + btcoexist->bt_info.miracast_plus_bt = false; + + chip_type = rtl_get_hwpg_bt_type(rtlpriv); + exhalbtc_set_chip_type(chip_type); + ant_num = rtl_get_hwpg_ant_num(rtlpriv); + exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num); + /* set default antenna position to main port */ + btcoexist->board_info.btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + single_ant_path = rtl_get_hwpg_single_ant_path(rtlpriv); + exhalbtc_set_single_ant_path(single_ant_path); + + if (rtl_get_hwpg_package_type(rtlpriv) == 0) + btcoexist->board_info.tfbga_package = false; + else if (rtl_get_hwpg_package_type(rtlpriv) == 1) + btcoexist->board_info.tfbga_package = false; + else + btcoexist->board_info.tfbga_package = true; + + if (btcoexist->board_info.tfbga_package) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Package Type = TFBGA\n"); + else + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Package Type = Non-TFBGA\n"); + + return true; +} + +void exhalbtc_power_on_setting(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_power_on++; + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_power_on_setting(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_power_on_setting(btcoexist); + } +} + +void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_pre_load_firmware++; + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_pre_load_firmware(btcoexist); + } +} + +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only) +{ if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_init_hw_config++; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_init_hwconfig(btcoexist); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_init_hwconfig(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_init_hwconfig(btcoexist, wifi_only); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_init_hwconfig(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_init_hwconfig(btcoexist, wifi_only); + } else if (IS_HARDWARE_TYPE_8723A(btcoexist->adapter)) { + /* 8723A has no this function */ + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_init_hwconfig(btcoexist); + } } void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_init_coex_dm++; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_init_coex_dm(btcoexist); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_init_coex_dm(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_init_coex_dm(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_init_coex_dm(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_init_coex_dm(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_init_coex_dm(btcoexist); + } btcoexist->initilized = true; } void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 ips_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -737,18 +1012,28 @@ void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) else ips_type = BTC_IPS_LEAVE; - halbtc_leave_low_power(); - - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_ips_notify(btcoexist, ips_type); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_ips_notify(btcoexist, ips_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_ips_notify(btcoexist, ips_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_ips_notify(btcoexist, ips_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_ips_notify(btcoexist, ips_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_ips_notify(btcoexist, ips_type); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 lps_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -762,14 +1047,24 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) else lps_type = BTC_LPS_ENABLE; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_lps_notify(btcoexist, lps_type); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_lps_notify(btcoexist, lps_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_lps_notify(btcoexist, lps_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_lps_notify(btcoexist, lps_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_lps_notify(btcoexist, lps_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_lps_notify(btcoexist, lps_type); + } } void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 scan_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -783,18 +1078,28 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) else scan_type = BTC_SCAN_FINISH; - halbtc_leave_low_power(); - - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_scan_notify(btcoexist, scan_type); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_scan_notify(btcoexist, scan_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_scan_notify(btcoexist, scan_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_scan_notify(btcoexist, scan_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_scan_notify(btcoexist, scan_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_scan_notify(btcoexist, scan_type); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 asso_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -808,10 +1113,24 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) else asso_type = BTC_ASSOCIATE_FINISH; - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_connect_notify(btcoexist, asso_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_connect_notify(btcoexist, asso_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_connect_notify(btcoexist, asso_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_connect_notify(btcoexist, asso_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_connect_notify(btcoexist, asso_type); + } - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_connect_notify(btcoexist, asso_type); + halbtc_normal_low_power(btcoexist); } void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, @@ -830,15 +1149,28 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, else status = BTC_MEDIA_DISCONNECT; - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_media_status_notify(btcoexist, status); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_media_status_notify(btcoexist, status); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_media_status_notify(btcoexist, status); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_media_status_notify(btcoexist, status); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_media_status_notify(btcoexist, status); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 packet_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -847,28 +1179,85 @@ void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) if (btcoexist->manual_control) return; - packet_type = BTC_PACKET_DHCP; - - halbtc_leave_low_power(); + if (pkt_type == PACKET_DHCP) { + packet_type = BTC_PACKET_DHCP; + } else if (pkt_type == PACKET_EAPOL) { + packet_type = BTC_PACKET_EAPOL; + } else if (pkt_type == PACKET_ARP) { + packet_type = BTC_PACKET_ARP; + } else { + packet_type = BTC_PACKET_UNKNOWN; + return; + } - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_special_packet_notify(btcoexist, - packet_type); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_special_packet_notify(btcoexist, + packet_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_special_packet_notify(btcoexist, + packet_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_special_packet_notify(btcoexist, + packet_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_special_packet_notify(btcoexist, + packet_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_special_packet_notify(btcoexist, + packet_type); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, u8 length) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_bt_info_notify++; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_bt_info_notify(btcoexist, tmp_buf, + length); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_bt_info_notify(btcoexist, tmp_buf, + length); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, + length); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_bt_info_notify(btcoexist, tmp_buf, + length); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_bt_info_notify(btcoexist, tmp_buf, + length); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_rf_status_notify(btcoexist, type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + } } void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) @@ -881,44 +1270,117 @@ void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) if (btcoexist->manual_control) return; - stack_op_type = BTC_STACK_OP_NONE; - - halbtc_leave_low_power(); - - halbtc_nomal_low_power(); + if ((type == HCI_BT_OP_INQUIRY_START) || + (type == HCI_BT_OP_PAGING_START) || + (type == HCI_BT_OP_PAIRING_START)) { + stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_START; + } else if ((type == HCI_BT_OP_INQUIRY_FINISH) || + (type == HCI_BT_OP_PAGING_SUCCESS) || + (type == HCI_BT_OP_PAGING_UNSUCCESS) || + (type == HCI_BT_OP_PAIRING_FINISH)) { + stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_FINISH; + } else { + stack_op_type = BTC_STACK_OP_NONE; + } } void exhalbtc_halt_notify(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); if (!halbtc_is_bt_coexist_available(btcoexist)) return; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_halt_notify(btcoexist); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_halt_notify(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_halt_notify(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_halt_notify(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_halt_notify(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_halt_notify(btcoexist); + } + + btcoexist->binded = false; } void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) { if (!halbtc_is_bt_coexist_available(btcoexist)) return; + + /* currently only 1ant we have to do the notification, + * once pnp is notified to sleep state, we have to leave LPS that + * we can sleep normally. + */ + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_pnp_notify(btcoexist, pnp_state); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_pnp_notify(btcoexist, pnp_state); + } else if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_pnp_notify(btcoexist, pnp_state); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_pnp_notify(btcoexist, pnp_state); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + } } -void exhalbtc_periodical(struct btc_coexist *btcoexist) +void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) return; - btcoexist->statistics.cnt_periodical++; + btcoexist->statistics.cnt_coex_dm_switch++; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) { + btcoexist->stop_coex_dm = true; + ex_btc8723b1ant_coex_dm_reset(btcoexist); + exhalbtc_set_ant_num(rtlpriv, + BT_COEX_ANT_TYPE_DETECTED, 2); + ex_btc8723b2ant_init_hwconfig(btcoexist); + ex_btc8723b2ant_init_coex_dm(btcoexist); + btcoexist->stop_coex_dm = false; + } + } - halbtc_leave_low_power(); + halbtc_normal_low_power(btcoexist); +} - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_periodical(btcoexist); +void exhalbtc_periodical(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_periodical++; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_periodical(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + if (!halbtc_under_ips(btcoexist)) + ex_btc8821a1ant_periodical(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_periodical(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_periodical(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_periodical(btcoexist); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_dbg_control(struct btc_coexist *btcoexist, @@ -927,6 +1389,17 @@ void exhalbtc_dbg_control(struct btc_coexist *btcoexist, if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_dbg_ctrl++; + + halbtc_leave_low_power(btcoexist); + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, + u32 offset, u32 span, u32 seconds) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; } void exhalbtc_stack_update_profile_info(void) @@ -964,11 +1437,6 @@ void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version) btcoexist->bt_info.bt_hci_ver = bt_hci_version; } -void exhalbtc_set_bt_exist(bool bt_exist) -{ - gl_bt_coexist.board_info.bt_exist = bt_exist; -} - void exhalbtc_set_chip_type(u8 chip_type) { switch (chip_type) { @@ -1002,25 +1470,8 @@ void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num) if (BT_COEX_ANT_TYPE_PG == type) { gl_bt_coexist.board_info.pg_ant_num = ant_num; gl_bt_coexist.board_info.btdm_ant_num = ant_num; - /* The antenna position: - * Main (default) or Aux for pgAntNum=2 && btdmAntNum =1. - * The antenna position should be determined by - * auto-detect mechanism. - * The following is assumed to main, - * and those must be modified - * if y auto-detect mechanism is ready - */ - if ((gl_bt_coexist.board_info.pg_ant_num == 2) && - (gl_bt_coexist.board_info.btdm_ant_num == 1)) - gl_bt_coexist.board_info.btdm_ant_pos = - BTC_ANTENNA_AT_MAIN_PORT; - else - gl_bt_coexist.board_info.btdm_ant_pos = - BTC_ANTENNA_AT_MAIN_PORT; } else if (BT_COEX_ANT_TYPE_ANTDIV == type) { gl_bt_coexist.board_info.btdm_ant_num = ant_num; - gl_bt_coexist.board_info.btdm_ant_pos = - BTC_ANTENNA_AT_MAIN_PORT; } else if (type == BT_COEX_ANT_TYPE_DETECTED) { gl_bt_coexist.board_info.btdm_ant_num = ant_num; if (rtlpriv->cfg->mod_params->ant_sel == 1) @@ -1032,13 +1483,33 @@ void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num) } } +/* Currently used by 8723b only, S0 or S1 */ +void exhalbtc_set_single_ant_path(u8 single_ant_path) +{ + gl_bt_coexist.board_info.single_ant_path = single_ant_path; +} + void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); if (!halbtc_is_bt_coexist_available(btcoexist)) return; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_display_coex_info(btcoexist); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_display_coex_info(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_display_coex_info(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_display_coex_info(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_display_coex_info(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_display_coex_info(btcoexist); + } + + halbtc_normal_low_power(btcoexist); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index c8271135aaaa..f9b87c12db09 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -30,6 +30,9 @@ #define NORMAL_EXEC false #define FORCE_EXEC true +#define BTC_RF_OFF 0x0 +#define BTC_RF_ON 0x1 + #define BTC_RF_A RF90_PATH_A #define BTC_RF_B RF90_PATH_B #define BTC_RF_C RF90_PATH_C @@ -150,6 +153,7 @@ struct btc_board_info { u8 btdm_ant_pos; u8 single_ant_path; /* current used for 8723b only, 1=>s0, 0=>s1 */ bool bt_exist; + bool tfbga_package; }; enum btc_dbg_opcode { @@ -196,6 +200,44 @@ enum btc_wifi_pnp { BTC_WIFI_PNP_MAX }; +enum btc_iot_peer { + BTC_IOT_PEER_UNKNOWN = 0, + BTC_IOT_PEER_REALTEK = 1, + BTC_IOT_PEER_REALTEK_92SE = 2, + BTC_IOT_PEER_BROADCOM = 3, + BTC_IOT_PEER_RALINK = 4, + BTC_IOT_PEER_ATHEROS = 5, + BTC_IOT_PEER_CISCO = 6, + BTC_IOT_PEER_MERU = 7, + BTC_IOT_PEER_MARVELL = 8, + BTC_IOT_PEER_REALTEK_SOFTAP = 9, + BTC_IOT_PEER_SELF_SOFTAP = 10, /* Self is SoftAP */ + BTC_IOT_PEER_AIRGO = 11, + BTC_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 12, + BTC_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 13, + BTC_IOT_PEER_MAX, +}; + +/* for 8723b-d cut large current issue */ +enum bt_wifi_coex_state { + BTC_WIFI_STAT_INIT, + BTC_WIFI_STAT_IQK, + BTC_WIFI_STAT_NORMAL_OFF, + BTC_WIFI_STAT_MP_OFF, + BTC_WIFI_STAT_NORMAL, + BTC_WIFI_STAT_ANT_DIV, + BTC_WIFI_STAT_MAX +}; + +enum bt_ant_type { + BTC_ANT_TYPE_0, + BTC_ANT_TYPE_1, + BTC_ANT_TYPE_2, + BTC_ANT_TYPE_3, + BTC_ANT_TYPE_4, + BTC_ANT_TYPE_MAX +}; + enum btc_get_type { /* type bool */ BTC_GET_BL_HS_OPERATION, @@ -216,6 +258,9 @@ enum btc_get_type { BTC_GET_BL_WIFI_UNDER_B_MODE, BTC_GET_BL_EXT_SWITCH, BTC_GET_BL_WIFI_IS_IN_MP_MODE, + BTC_GET_BL_IS_ASUS_8723B, + BTC_GET_BL_FW_READY, + BTC_GET_BL_RF4CE_CONNECTED, /* type s4Byte */ BTC_GET_S4_WIFI_RSSI, @@ -228,6 +273,11 @@ enum btc_get_type { BTC_GET_U4_WIFI_LINK_STATUS, BTC_GET_U4_BT_PATCH_VER, BTC_GET_U4_VENDOR, + BTC_GET_U4_SUPPORTED_VERSION, + BTC_GET_U4_SUPPORTED_FEATURE, + BTC_GET_U4_WIFI_IQK_TOTAL, + BTC_GET_U4_WIFI_IQK_OK, + BTC_GET_U4_WIFI_IQK_FAIL, /* type u1Byte */ BTC_GET_U1_WIFI_DOT11_CHNL, @@ -235,6 +285,8 @@ enum btc_get_type { BTC_GET_U1_WIFI_HS_CHNL, BTC_GET_U1_MAC_PHY_MODE, BTC_GET_U1_AP_NUM, + BTC_GET_U1_ANT_TYPE, + BTC_GET_U1_IOT_PEER, /* for 1Ant */ BTC_GET_U1_LPS_MODE, @@ -293,6 +345,7 @@ enum btc_set_type { /* BT Coex related */ BTC_SET_ACT_CTRL_BT_INFO, BTC_SET_ACT_CTRL_BT_COEX, + BTC_SET_ACT_CTRL_8723B_ANT, /***************************/ BTC_SET_MAX }; @@ -411,12 +464,18 @@ struct btc_bt_info { bool bt_disabled; u8 rssi_adjust_for_agc_table_on; u8 rssi_adjust_for_1ant_coex_type; + bool pre_bt_ctrl_agg_buf_size; bool bt_busy; + u8 pre_agg_buf_size; u8 agg_buf_size; bool limited_dig; + bool pre_reject_agg_pkt; bool reject_agg_pkt; bool bt_ctrl_buf_size; bool increase_scan_dev_num; + bool miracast_plus_bt; + bool bt_ctrl_agg_buf_size; + bool bt_tx_rx_mask; u16 bt_hci_ver; u16 bt_real_fw_ver; u8 bt_fw_ver; @@ -464,10 +523,13 @@ struct btc_statistics { u32 cnt_coex_dm_switch; u32 cnt_stack_operation_notify; u32 cnt_dbg_ctrl; + u32 cnt_pre_load_firmware; + u32 cnt_power_on; }; struct btc_bt_link_info { bool bt_link_exist; + bool bt_hi_pri_link_exist; bool sco_exist; bool sco_only; bool a2dp_exist; @@ -496,6 +558,11 @@ struct btc_coexist { enum btc_chip_interface chip_interface; struct btc_bt_link_info bt_link_info; + /* boolean variables to replace BT_AUTO_REPORT_ONLY_XXXXY_ZANT + * configuration parameters + */ + bool auto_report_1ant; + bool auto_report_2ant; bool initilized; bool stop_coex_dm; bool manual_control; @@ -532,8 +599,9 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); extern struct btc_coexist gl_bt_coexist; -bool exhalbtc_initlize_variables(struct rtl_priv *adapter); -void exhalbtc_init_hw_config(struct btc_coexist *btcoexist); +bool exhalbtc_initlize_variables(void); +bool exhalbtc_bind_bt_coex_withadapter(void *adapter); +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only); void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist); void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type); @@ -563,5 +631,6 @@ void exhalbtc_signal_compensation(struct btc_coexist *btcoexist, u8 *rssi_wifi, u8 *rssi_bt); void exhalbtc_lps_leave(struct btc_coexist *btcoexist); void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist); +void exhalbtc_set_single_ant_path(u8 single_ant_path); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 46e0fa6be273..4366c9817e1e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -45,42 +45,79 @@ static struct rtl_btc_ops rtl_btc_operation = { .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo, .btc_is_bt_disabled = rtl_btc_is_bt_disabled, .btc_special_packet_notify = rtl_btc_special_packet_notify, + .btc_record_pwr_mode = rtl_btc_record_pwr_mode, + .btc_get_lps_val = rtl_btc_get_lps_val, + .btc_get_rpwm_val = rtl_btc_get_rpwm_val, + .btc_is_bt_ctrl_lps = rtl_btc_is_bt_ctrl_lps, + .btc_is_bt_lps_on = rtl_btc_is_bt_lps_on, + .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg, }; -void rtl_btc_init_variables(struct rtl_priv *rtlpriv) +void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len) { - exhalbtc_initlize_variables(rtlpriv); + u8 safe_len; + + safe_len = sizeof(gl_bt_coexist.pwr_mode_val); + + if (safe_len > len) + safe_len = len; + + memcpy(gl_bt_coexist.pwr_mode_val, buf, safe_len); } -void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) +u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv) { - u8 ant_num; - u8 bt_exist; - u8 bt_type; + return gl_bt_coexist.bt_info.lps_val; +} - ant_num = rtl_get_hwpg_ant_num(rtlpriv); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "%s, antNum is %d\n", __func__, ant_num); +u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.rpwm_val; +} - bt_exist = rtl_get_hwpg_bt_exist(rtlpriv); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "%s, bt_exist is %d\n", __func__, bt_exist); - exhalbtc_set_bt_exist(bt_exist); +bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.bt_ctrl_lps; +} + +bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.bt_lps_on; +} - bt_type = rtl_get_hwpg_bt_type(rtlpriv); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%s, bt_type is %d\n", - __func__, bt_type); - exhalbtc_set_chip_type(bt_type); +void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size) +{ + if (reject_agg) + *reject_agg = gl_bt_coexist.bt_info.reject_agg_pkt; + if (ctrl_agg_size) + *ctrl_agg_size = gl_bt_coexist.bt_info.bt_ctrl_agg_buf_size; + if (agg_size) + *agg_size = gl_bt_coexist.bt_info.agg_buf_size; +} - if (rtlpriv->cfg->mod_params->ant_sel == 1) - exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_DETECTED, 1); - else - exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num); +void rtl_btc_init_variables(struct rtl_priv *rtlpriv) +{ + exhalbtc_initlize_variables(); + exhalbtc_bind_bt_coex_withadapter(rtlpriv); +} + +void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) +{ + /* move ant_num, bt_type and single_ant_path to + * exhalbtc_bind_bt_coex_withadapter() + */ } void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) { - exhalbtc_init_hw_config(&gl_bt_coexist); + u8 bt_exist; + + bt_exist = rtl_get_hwpg_bt_exist(rtlpriv); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "%s, bt_exist is %d\n", __func__, bt_exist); + + exhalbtc_init_hw_config(&gl_bt_coexist, !bt_exist); exhalbtc_init_coex_dm(&gl_bt_coexist); } @@ -118,7 +155,9 @@ void rtl_btc_periodical(struct rtl_priv *rtlpriv) void rtl_btc_halt_notify(void) { - exhalbtc_halt_notify(&gl_bt_coexist); + struct btc_coexist *btcoexist = &gl_bt_coexist; + + exhalbtc_halt_notify(btcoexist); } void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h index fff5117e1c4e..6fe521cbe7f0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h @@ -43,6 +43,13 @@ bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); +void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len); +u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv); +u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv); +void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size); struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index a4f8e326a2bc..b0ad061048c5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -629,7 +629,8 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) } /*For LPS */ - if (changed & IEEE80211_CONF_CHANGE_PS) { + if ((changed & IEEE80211_CONF_CHANGE_PS) && + rtlpriv->psc.swctrl_lps && !rtlpriv->psc.fwctrl_lps) { cancel_delayed_work(&rtlpriv->works.ps_work); cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); if (conf->flags & IEEE80211_CONF_PS) { @@ -1463,6 +1464,9 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n"); mac->act_scanning = false; mac->skip_scan = false; + + rtlpriv->btcoexist.btc_info.ap_num = rtlpriv->scan_list.num; + if (rtlpriv->link_info.higher_busytraffic) return; @@ -1670,6 +1674,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, *so don't use rtl_cam_reset_all_entry *or clear all entry here. */ + rtl_wait_tx_report_acked(hw, 500); /* wait 500ms for TX ack */ + rtl_cam_delete_one_entry(hw, mac_addr, key_idx); break; default: diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.c b/drivers/net/wireless/realtek/rtlwifi/debug.c index 7ecac6116d5d..38fef6dbb44b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/debug.c +++ b/drivers/net/wireless/realtek/rtlwifi/debug.c @@ -27,7 +27,7 @@ #include <linux/moduleparam.h> #ifdef CONFIG_RTLWIFI_DEBUG -void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level, +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level, const char *fmt, ...) { if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) && diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.h b/drivers/net/wireless/realtek/rtlwifi/debug.h index bf5339f1c1bc..947718001457 100644 --- a/drivers/net/wireless/realtek/rtlwifi/debug.h +++ b/drivers/net/wireless/realtek/rtlwifi/debug.h @@ -105,6 +105,7 @@ #define COMP_EASY_CONCURRENT COMP_USB /* reuse of this bit is OK */ #define COMP_BT_COEXIST BIT(30) #define COMP_IQK BIT(31) +#define COMP_TX_REPORT BIT_ULL(32) /*-------------------------------------------------------------- Define the rt_print components @@ -169,7 +170,7 @@ enum dbgp_flag_e { struct rtl_priv; __printf(4, 5) -void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level, +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level, const char *fmt, ...); __printf(4, 5) @@ -198,7 +199,7 @@ struct rtl_priv; __printf(4, 5) static inline void RT_TRACE(struct rtl_priv *rtlpriv, - int comp, int level, + u64 comp, int level, const char *fmt, ...) { } @@ -211,7 +212,7 @@ static inline void RTPRINT(struct rtl_priv *rtlpriv, } static inline void RT_PRINT_DATA(struct rtl_priv *rtlpriv, - int comp, int level, + u64 comp, int level, const char *titlestring, const void *hexdata, size_t hexdatalen) { diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 2e6b888bd417..032b6317690d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -729,14 +729,12 @@ static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw, dev_kfree_skb_any(skb); } else { struct sk_buff *uskb = NULL; - u8 *pdata; uskb = dev_alloc_skb(skb->len + 128); if (likely(uskb)) { memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status)); - pdata = (u8 *)skb_put(uskb, skb->len); - memcpy(pdata, skb->data, skb->len); + skb_put_data(uskb, skb->data, skb->len); dev_kfree_skb_any(skb); ieee80211_rx_irqsafe(hw, uskb); } else { @@ -881,6 +879,9 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) if (unicast) rtlpriv->link_info.num_rx_inperiod++; } + + rtl_collect_scan_list(hw, skb); + /* static bcn for roaming */ rtl_beacon_statistic(hw, skb); rtl_p2p_info(hw, (void *)skb->data, skb->len); @@ -1826,6 +1827,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw) rtlpci->driver_is_goingto_unload = false; if (rtlpriv->cfg->ops->get_btc_status && rtlpriv->cfg->ops->get_btc_status()) { + rtlpriv->btcoexist.btc_info.ap_num = 36; rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv); } diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 0d152877d969..07ee3096f50e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -356,7 +356,7 @@ void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) if (mac->link_state != MAC80211_LINKED) return; - if (ppsc->dot11_psmode == rt_psmode) + if (ppsc->dot11_psmode == rt_psmode && rt_psmode == EACTIVE) return; /* Update power save mode configured. */ @@ -438,11 +438,13 @@ static void rtl_lps_enter_core(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->dot11_psmode == EACTIVE) { - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, - "Enter 802.11 power save mode...\n"); - rtl_lps_set_psmode(hw, EAUTOPS); - } + /* Don't need to check (ppsc->dot11_psmode == EACTIVE), because + * bt_ccoexist may ask to enter lps. + * In normal case, this constraint move to rtl_lps_set_psmode(). + */ + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Enter 802.11 power save mode...\n"); + rtl_lps_set_psmode(hw, EAUTOPS); spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c index 21ed9ad3be7a..a2eca669873b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c @@ -620,8 +620,7 @@ void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u1rsvdpageloc, 3); skb = dev_alloc_skb(totalpacketlen); - memcpy(skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h index 15400ee6c04b..0c0d64aea651 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h @@ -248,7 +248,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -256,6 +255,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 7661cfa53032..774e72058d24 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -270,7 +270,7 @@ static struct rtl_hal_ops rtl8188ee_hal_ops = { static struct rtl_mod_params rtl88ee_mod_params = { .sw_crypto = false, - .inactiveps = false, + .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = false, .msi_support = true, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c index c7a77467b20e..015476e3f7e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c @@ -647,8 +647,7 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); if (cmd_send_packet) rtstatus = cmd_send_packet(hw, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h index 1bb7ed35812d..9e3b58a5d2bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h @@ -227,7 +227,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -235,6 +234,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index 41422e4da8b7..de6c3428f7c6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -512,7 +512,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); - txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); + txdesc = skb_push(skb, RTL_TX_HEADER_SIZE); memset(txdesc, 0, RTL_TX_HEADER_SIZE); SET_TX_DESC_PKT_SIZE(txdesc, pktlen); SET_TX_DESC_LINIP(txdesc, 0); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c index 88faeab2574f..f4129cf96e7c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c @@ -668,8 +668,7 @@ void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) if (!skb) { dlok = false; } else { - memcpy((u8 *) skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = _rtl92d_cmd_send_packet(hw, skb); if (rtstatus) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h index b354b95936e2..d4c4e76a9244 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h @@ -255,7 +255,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -263,6 +262,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 1f42ce5f8f27..f5d4df985c37 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -422,28 +422,86 @@ void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm , power_state = 0; + u8 rlbm, power_state = 0, byte5 = 0; + u8 awake_intvl; /* DTIM = (awake_intvl - 1) */ + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); + bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_lps_on(rtlpriv) : false); + + if (bt_ctrl_lps) + mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", + mode, bt_ctrl_lps); + + switch (mode) { + case FW_PS_MIN_MODE: + rlbm = 0; + awake_intvl = 2; + break; + case FW_PS_MAX_MODE: + rlbm = 1; + awake_intvl = 2; + break; + case FW_PS_DTIM_MODE: + rlbm = 2; + awake_intvl = ppsc->reg_max_lps_awakeintvl; + /* hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period + * is only used in swlps. + */ + break; + default: + rlbm = 2; + awake_intvl = 4; + break; + } - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode); + if (rtlpriv->mac80211.p2p) { + awake_intvl = 2; + rlbm = 1; + } + + if (mode == FW_PS_ACTIVE_MODE) { + byte5 = 0x40; + power_state = FW_PWR_STATE_ACTIVE; + } else { + if (bt_ctrl_lps) { + byte5 = btc_ops->btc_get_lps_val(rtlpriv); + power_state = btc_ops->btc_get_rpwm_val(rtlpriv); + + if ((rlbm == 2) && (byte5 & BIT(4))) { + /* Keep awake interval to 1 to prevent from + * decreasing coex performance + */ + awake_intvl = 2; + rlbm = 2; + } + } else { + byte5 = 0x40; + power_state = FW_PWR_STATE_RF_OFF; + } + } SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); - rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, - (rtlpriv->mac80211.p2p) ? - ppsc->smart_ps : 1); + bt_ctrl_lps ? 0 : + ((rtlpriv->mac80211.p2p) ? + ppsc->smart_ps : 1)); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); + awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); - if (mode == FW_PS_ACTIVE_MODE) - power_state |= FW_PWR_STATE_ACTIVE; - else - power_state |= FW_PWR_STATE_RF_OFF; SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode, + H2C_92E_PWEMODE_LENGTH); rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH, u1_h2c_set_pwrmode); } @@ -708,8 +766,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u1rsvdpageloc, 3); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); b_dlok = true; @@ -843,6 +900,7 @@ void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, case C2H_8192E_TX_REPORT: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE , "[C2H], C2H_8723BE_TX_REPORT!\n"); + rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; case C2H_8192E_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h index af8271967a88..b770f722daa6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h @@ -37,7 +37,7 @@ #define USE_OLD_WOWLAN_DEBUG_FW 0 #define H2C_92E_RSVDPAGE_LOC_LEN 5 -#define H2C_92E_PWEMODE_LENGTH 5 +#define H2C_92E_PWEMODE_LENGTH 7 #define H2C_92E_JOINBSSRPT_LENGTH 1 #define H2C_92E_AP_OFFLOAD_LENGTH 3 #define H2C_92E_WOWLAN_LENGTH 3 @@ -154,6 +154,8 @@ enum rtl8192e_c2h_evt { SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __val) #define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __val) \ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BYTE5(__cmd, __val) \ + SET_BITS_TO_LE_1BYTE((__cmd) + 5, 0, 8, __val) #define GET_92E_H2CCMD_PWRMODE_PARM_MODE(__cmd) \ LE_BITS_TO_1BYTE(__cmd, 0, 8) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index 6f5098a18655..d84ac7adfd82 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1670,7 +1670,8 @@ void rtl92ee_card_disable(struct ieee80211_hw *hw) _rtl92ee_poweroff_adapter(hw); /* after power off we should do iqk again */ - rtlpriv->phy.iqk_initialized = false; + if (!rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->phy.iqk_initialized = false; } void rtl92ee_interrupt_recognized(struct ieee80211_hw *hw, @@ -2506,7 +2507,7 @@ void rtl92ee_set_key(struct ieee80211_hw *hw, u32 key_index, "add one entry\n"); if (is_pairwise) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - "set Pairwiase key\n"); + "set Pairwise key\n"); rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 48820bc497d8..eaa503b7c4b4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -253,7 +253,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { static struct rtl_mod_params rtl92ee_mod_params = { .sw_crypto = false, - .inactiveps = false, + .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = true, .msi_support = true, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index b1864bb07c2c..55f238a2a310 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -731,6 +731,9 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } + /* tx report */ + rtl_get_tx_report(ptcb_desc, pdesc, hw); + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ieee80211_is_mgmt(fc)) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h index 8053d1b12ec4..b0105c529010 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h @@ -159,7 +159,7 @@ #define SET_TX_DESC_NULL_0(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 1, __val) #define SET_TX_DESC_NULL_1(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 15, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 15, 1, __val) #define SET_TX_DESC_BK(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val) #define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ @@ -167,7 +167,7 @@ #define SET_TX_DESC_RAW(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) #define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) #define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) #define SET_TX_DESC_BT_NULL(__pdesc, __val) \ @@ -252,15 +252,15 @@ /* Dword 6 */ #define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 12, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) #define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 16, 3, __val) #define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 19, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 19, 3, __val) #define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 22, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 22, 3, __val) #define SET_TX_DESC_ANTSEL_D(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 25, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 25, 3, __val) /* Dword 7 */ #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c index 89a0a28b8b20..e7b1d7c0f542 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c @@ -188,10 +188,9 @@ static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, if (!skb) return false; skb_reserve(skb, extra_descoffset); - seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - - extra_descoffset)); - memcpy(seg_ptr, code_virtual_address + frag_offset, - (u32)(frag_length - extra_descoffset)); + seg_ptr = skb_put_data(skb, + code_virtual_address + frag_offset, + (u32)(frag_length - extra_descoffset)); tcb_desc = (struct rtl_tcb_desc *)(skb->cb); tcb_desc->queue_index = TXCMD_QUEUE; @@ -463,7 +462,7 @@ static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, break; /* Clear content */ - ph2c_buffer = (u8 *)skb_put(skb, (u32)len); + ph2c_buffer = skb_put(skb, (u32)len); memset((ph2c_buffer + totallen + tx_desclen), 0, len); /* CMD len */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c index a954a87b0ed9..bf9859f74b6f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c @@ -470,8 +470,7 @@ void rtl8723e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u1rsvdpageloc, 3); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 859c045bd37c..5ac7b815648a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -2264,7 +2264,7 @@ void rtl8723e_set_key(struct ieee80211_hw *hw, u32 key_index, "add one entry\n"); if (is_pairwise) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - "set Pairwiase key\n"); + "set Pairwise key\n"); rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, @@ -2313,7 +2313,7 @@ static void rtl8723e_bt_var_init(struct ieee80211_hw *hw) rtlpriv->btcoexist.eeprom_bt_radio_shared; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, - "BT Coexistance = 0x%x\n", + "BT Coexistence = 0x%x\n", rtlpriv->btcoexist.bt_coexistence); if (rtlpriv->btcoexist.bt_coexistence) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h index 306059f9b9cc..30938cd9fce5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h @@ -217,7 +217,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -225,6 +224,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index 4fc839b1d601..dd6f95cfaec9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -240,27 +240,84 @@ void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm, power_state = 0; - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + u8 rlbm, power_state = 0, byte5 = 0; + u8 awake_intvl; /* DTIM = (awake_intvl - 1) */ + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); + bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_lps_on(rtlpriv) : false); + + if (bt_ctrl_lps) + mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", + mode, bt_ctrl_lps); + + switch (mode) { + case FW_PS_MIN_MODE: + rlbm = 0; + awake_intvl = 2; + break; + case FW_PS_MAX_MODE: + rlbm = 1; + awake_intvl = 2; + break; + case FW_PS_DTIM_MODE: + rlbm = 2; + awake_intvl = ppsc->reg_max_lps_awakeintvl; + /* hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period + * is only used in swlps. + */ + break; + default: + rlbm = 2; + awake_intvl = 4; + break; + } + + if (rtlpriv->mac80211.p2p) { + awake_intvl = 2; + rlbm = 1; + } + + if (mode == FW_PS_ACTIVE_MODE) { + byte5 = 0x40; + power_state = FW_PWR_STATE_ACTIVE; + } else { + if (bt_ctrl_lps) { + byte5 = btc_ops->btc_get_lps_val(rtlpriv); + power_state = btc_ops->btc_get_rpwm_val(rtlpriv); + + if ((rlbm == 2) && (byte5 & BIT(4))) { + /* Keep awake interval to 1 to prevent from + * decreasing coex performance + */ + awake_intvl = 2; + rlbm = 2; + } + } else { + byte5 = 0x40; + power_state = FW_PWR_STATE_RF_OFF; + } + } SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); - rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, - (rtlpriv->mac80211.p2p) ? - ppsc->smart_ps : 1); + bt_ctrl_lps ? 0 : ppsc->smart_ps); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); + awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); - if (mode == FW_PS_ACTIVE_MODE) - power_state |= FW_PWR_STATE_ACTIVE; - else - power_state |= FW_PWR_STATE_RF_OFF; SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", u1_h2c_set_pwrmode, H2C_PWEMODE_LENGTH); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode, + H2C_PWEMODE_LENGTH); rtl8723be_fill_h2c_cmd(hw, H2C_8723B_SETPWRMODE, H2C_PWEMODE_LENGTH, u1_h2c_set_pwrmode); } @@ -527,8 +584,7 @@ void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, u1rsvdpageloc, sizeof(u1rsvdpageloc)); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); @@ -662,6 +718,7 @@ void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, case C2H_8723B_TX_REPORT: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_TX_REPORT!\n"); + rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; case C2H_8723B_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h index 2482b3bc2bfa..2de4edb62bca 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h @@ -33,7 +33,7 @@ #define USE_OLD_WOWLAN_DEBUG_FW 0 -#define H2C_PWEMODE_LENGTH 5 +#define H2C_PWEMODE_LENGTH 7 /* Fw PS state for RPWM. *BIT[2:0] = HW state @@ -125,6 +125,8 @@ enum rtl8723b_c2h_evt { SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val) #define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__ph2ccmd, __val) \ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BYTE5(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 5, 0, 8, __val) #define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd) \ LE_BITS_TO_1BYTE(__ph2ccmd, 0, 8) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 1acbfb86472c..2a7ad5ffe997 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -846,6 +846,9 @@ static bool _rtl8723be_init_mac(struct ieee80211_hw *hw) return false; } + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_power_on_setting(rtlpriv); + bytetmp = rtl_read_byte(rtlpriv, REG_MULTI_FUNC_CTRL); rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, bytetmp | BIT(3)); @@ -1440,7 +1443,9 @@ int rtl8723be_hw_init(struct ieee80211_hw *hw) */ if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2 || !rtlpriv->cfg->ops->get_btc_status()) { - rtl8723be_phy_iq_calibrate(hw, false); + rtl8723be_phy_iq_calibrate(hw, + (rtlphy->iqk_initialized ? + true : false)); rtlphy->iqk_initialized = true; } rtl8723be_dm_check_txpower_tracking(hw); @@ -1674,7 +1679,8 @@ void rtl8723be_card_disable(struct ieee80211_hw *hw) _rtl8723be_poweroff_adapter(hw); /* after power off we should do iqk again */ - rtlpriv->phy.iqk_initialized = false; + if (!rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->phy.iqk_initialized = false; } void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw, @@ -2637,7 +2643,7 @@ void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index, "add one entry\n"); if (is_pairwise) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - "set Pairwiase key\n"); + "set Pairwise key\n"); rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c index ab0f39e46e1b..9752175cc466 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c @@ -2352,7 +2352,7 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) if (b_recovery) { rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9); - return; + goto label_done; } /* Save RF Path */ path_sel_bb = rtl_get_bbreg(hw, 0x948, MASKDWORD); @@ -2460,6 +2460,7 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) rtl_set_bbreg(hw, 0x948, MASKDWORD, path_sel_bb); /* rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff, path_sel_rf); */ +label_done: spin_lock(&rtlpriv->locks.iqk_lock); rtlphy->lck_inprogress = false; spin_unlock(&rtlpriv->locks.iqk_lock); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h index 03581d2a5da0..95c4f8e206c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h @@ -261,7 +261,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -269,6 +268,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 8c0ac96b5430..f9d10f1e7cf8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -155,8 +155,8 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); - rtlpriv->psc.reg_fwctrl_lps = 3; - rtlpriv->psc.reg_max_lps_awakeintvl = 5; + rtlpriv->psc.reg_fwctrl_lps = 2; + rtlpriv->psc.reg_max_lps_awakeintvl = 2; /* for ASPM, you can close aspm through * set const_support_pciaspm = 0 */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c index 3c6ce994c6aa..0e8944119652 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c @@ -488,6 +488,9 @@ void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } + /* tx report */ + rtl_get_tx_report(ptcb_desc, pdesc, hw); + /* ptcb_desc->use_driver_rate = true; */ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->hw_rate > DESC92C_RATEMCS0) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h index 8a9fe41ac15b..0274659f48ed 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h @@ -107,7 +107,7 @@ #define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val) #define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 14, 2, __val) #define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val) #define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ @@ -115,7 +115,7 @@ #define SET_TX_DESC_RAW(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) #define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) #define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) #define SET_TX_DESC_BT_INT(__pdesc, __val) \ @@ -187,6 +187,18 @@ #define SET_TX_DESC_RTS_SC(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) +#define SET_TX_DESC_MBSSID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 12, 4, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 16, 3, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 19, 3, __val) +#define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 22, 3, __val) +#define SET_TX_DESC_ANTSEL_D(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 25, 3, __val) #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 73350103b736..03259aa150fd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -489,29 +489,86 @@ void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_8821AE_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm, power_state = 0; + u8 rlbm, power_state = 0, byte5 = 0; + u8 awake_intvl; /* DTIM = (awake_intvl - 1) */ + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); + bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_lps_on(rtlpriv) : false); + + if (bt_ctrl_lps) + mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", + mode, bt_ctrl_lps); + + switch (mode) { + case FW_PS_MIN_MODE: + rlbm = 0; + awake_intvl = 2; + break; + case FW_PS_MAX_MODE: + rlbm = 1; + awake_intvl = 2; + break; + case FW_PS_DTIM_MODE: + rlbm = 2; + awake_intvl = ppsc->reg_max_lps_awakeintvl; + /* hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period + * is only used in swlps. + */ + break; + default: + rlbm = 2; + awake_intvl = 4; + break; + } - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + if (rtlpriv->mac80211.p2p) { + awake_intvl = 2; + rlbm = 1; + } + + if (mode == FW_PS_ACTIVE_MODE) { + byte5 = 0x40; + power_state = FW_PWR_STATE_ACTIVE; + } else { + if (bt_ctrl_lps) { + byte5 = btc_ops->btc_get_lps_val(rtlpriv); + power_state = btc_ops->btc_get_rpwm_val(rtlpriv); + + if ((rlbm == 2) && (byte5 & BIT(4))) { + /* Keep awake interval to 1 to prevent from + * decreasing coex performance + */ + awake_intvl = 2; + rlbm = 2; + } + } else { + byte5 = 0x40; + power_state = FW_PWR_STATE_RF_OFF; + } + } SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); - rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, - (rtlpriv->mac80211.p2p) ? - ppsc->smart_ps : 1); + bt_ctrl_lps ? 0 : + ((rtlpriv->mac80211.p2p) ? + ppsc->smart_ps : 1)); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); + awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); - if (mode == FW_PS_ACTIVE_MODE) - power_state |= FW_PWR_STATE_ACTIVE; - else - power_state |= FW_PWR_STATE_RF_OFF; - SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", u1_h2c_set_pwrmode, H2C_8821AE_PWEMODE_LENGTH); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode, + H2C_8821AE_PWEMODE_LENGTH); rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_SETPWRMODE, H2C_8821AE_PWEMODE_LENGTH, u1_h2c_set_pwrmode); @@ -1588,8 +1645,7 @@ out: &reserved_page_packet_8812[0], totalpacketlen); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet_8812, totalpacketlen); + skb_put_data(skb, &reserved_page_packet_8812, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); @@ -1725,8 +1781,7 @@ out: &reserved_page_packet_8821[0], totalpacketlen); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet_8821, totalpacketlen); + skb_put_data(skb, &reserved_page_packet_8821, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); @@ -1873,6 +1928,9 @@ void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, case C2H_8812_DBG: RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_8812_DBG!!\n"); break; + case C2H_8812_TX_REPORT: + rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); + break; case C2H_8812_RA_RPT: rtl8821ae_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h index 98d871afd92a..32d46d7128f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h @@ -42,7 +42,7 @@ #define USE_OLD_WOWLAN_DEBUG_FW 0 #define H2C_8821AE_RSVDPAGE_LOC_LEN 5 -#define H2C_8821AE_PWEMODE_LENGTH 5 +#define H2C_8821AE_PWEMODE_LENGTH 7 #define H2C_8821AE_JOINBSSRPT_LENGTH 1 #define H2C_8821AE_AP_OFFLOAD_LENGTH 3 #define H2C_8821AE_WOWLAN_LENGTH 3 @@ -218,6 +218,8 @@ enum rtl8821a_h2c_cmd { SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value) #define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __value) \ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value) +#define SET_H2CCMD_PWRMODE_PARM_BYTE5(__cmd, __value) \ + SET_BITS_TO_LE_1BYTE((__cmd) + 5, 0, 8, __value) #define GET_8821AE_H2CCMD_PWRMODE_PARM_MODE(__cmd) \ LE_BITS_TO_1BYTE(__cmd, 0, 8) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h index ed69dbe178ff..db8bc8a2de61 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h @@ -267,7 +267,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -275,6 +274,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index abaf34cb1433..d71d2776ca03 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -172,8 +172,8 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); - rtlpriv->psc.reg_fwctrl_lps = 3; - rtlpriv->psc.reg_max_lps_awakeintvl = 5; + rtlpriv->psc.reg_fwctrl_lps = 2; + rtlpriv->psc.reg_max_lps_awakeintvl = 2; /* for ASPM, you can close aspm through * set const_support_pciaspm = 0 diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c index 03665e82065f..749818929e8f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c @@ -740,6 +740,9 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } + /* tx report */ + rtl_get_tx_report(ptcb_desc, pdesc, hw); + /* ptcb_desc->use_driver_rate = true; */ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->hw_rate > DESC_RATEMCS0) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h index b6f3c564b8d1..9843a616dcec 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h @@ -114,7 +114,7 @@ #define SET_TX_DESC_RAW(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) #define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) #define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) #define SET_TX_DESC_BT_INT(__pdesc, __val) \ @@ -185,8 +185,21 @@ #define SET_TX_DESC_RTS_SC(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 16, 3, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 19, 3, __val) +#define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 22, 3, __val) +#define SET_TX_DESC_ANTSEL_D(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 25, 3, __val) +#define SET_TX_DESC_MBSSID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(i(__pdesc) + 24, 12, 4, __val) + #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 28, 0, 16, __val) #define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \ LE_BITS_TO_4BYTE(__pdesc+28, 0, 16) diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 4d989b8ab185..5590d07d0918 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -653,7 +653,7 @@ static void _rtl_rx_completed(struct urb *_urb) /* reserve some space for mac80211's radiotap */ skb_reserve(skb, __RADIO_TAP_SIZE_RSV); - memcpy(skb_put(skb, size), _urb->transfer_buffer, size); + skb_put_data(skb, _urb->transfer_buffer, size); skb_queue_tail(&rtlusb->rx_queue, skb); tasklet_schedule(&rtlusb->rx_work_tasklet); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index c0d2601bc55f..fb1ebb01133f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1886,6 +1886,13 @@ struct rtl_efuse { u8 channel_plan; }; +struct rtl_tx_report { + atomic_t sn; + u16 last_sent_sn; + unsigned long last_sent_time; + u16 last_recv_sn; +}; + struct rtl_ps_ctl { bool pwrdomain_protect; bool in_powersavemode; @@ -2075,6 +2082,8 @@ struct rtl_tcb_desc { u8 use_driver_rate:1; u8 disable_ratefallback:1; + u8 use_spe_rpt:1; + u8 ratr_index; u8 mac_id; u8 hw_rate; @@ -2324,6 +2333,7 @@ struct rtl_locks { spinlock_t entry_list_lock; spinlock_t usb_lock; spinlock_t c2hcmd_lock; + spinlock_t scan_list_lock; /* lock for the scan list */ /*FW clock change */ spinlock_t fw_ps_lock; @@ -2472,6 +2482,9 @@ struct rtl_btc_info { u8 btcoexist; u8 ant_num; u8 single_ant_path; + + u8 ap_num; + bool in_4way; }; struct bt_coexist_info { @@ -2534,6 +2547,7 @@ struct bt_coexist_info { struct rtl_btc_ops { void (*btc_init_variables) (struct rtl_priv *rtlpriv); void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv); + void (*btc_power_on_setting)(struct rtl_priv *rtlpriv); void (*btc_init_hw_config) (struct rtl_priv *rtlpriv); void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type); void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type); @@ -2550,6 +2564,13 @@ struct rtl_btc_ops { bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv); void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, u8 pkt_type); + void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len); + u8 (*btc_get_lps_val)(struct rtl_priv *rtlpriv); + u8 (*btc_get_rpwm_val)(struct rtl_priv *rtlpriv); + bool (*btc_is_bt_ctrl_lps)(struct rtl_priv *rtlpriv); + void (*btc_get_ampdu_cfg)(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size); + bool (*btc_is_bt_lps_on)(struct rtl_priv *rtlpriv); }; struct proxim { @@ -2568,6 +2589,17 @@ struct rtl_c2hcmd { u8 *val; }; +struct rtl_bssid_entry { + struct list_head list; + u8 bssid[ETH_ALEN]; + u32 age; +}; + +struct rtl_scan_list { + int num; + struct list_head list; /* sort by age */ +}; + struct rtl_priv { struct ieee80211_hw *hw; struct completion firmware_loading_complete; @@ -2588,6 +2620,8 @@ struct rtl_priv { struct rtl_security sec; struct rtl_efuse efuse; struct rtl_led_ctl ledctl; + struct rtl_tx_report tx_report; + struct rtl_scan_list scan_list; struct rtl_ps_ctl psc; struct rate_adaptive ra; diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile index 25828b692756..a475c813674a 100644 --- a/drivers/net/wireless/rsi/Makefile +++ b/drivers/net/wireless/rsi/Makefile @@ -2,7 +2,7 @@ rsi_91x-y += rsi_91x_main.o rsi_91x-y += rsi_91x_core.o rsi_91x-y += rsi_91x_mac80211.o rsi_91x-y += rsi_91x_mgmt.o -rsi_91x-y += rsi_91x_pkt.o +rsi_91x-y += rsi_91x_hal.o rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index f3d3995d8f6b..68f04a76769e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -306,7 +306,7 @@ void rsi_core_qos_processor(struct rsi_common *common) tstamp_2 = jiffies; mutex_unlock(&common->tx_rxlock); - if (tstamp_2 > tstamp_1 + (300 * HZ / 1000)) + if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000)) schedule(); } } diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index 828a042f903f..4c0a493bd44e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -125,7 +125,9 @@ static int rsi_stats_read(struct seq_file *seq, void *data) struct rsi_common *common = seq->private; unsigned char fsm_state[][32] = { + "FSM_FW_NOT_LOADED", "FSM_CARD_NOT_READY", + "FSM_COMMON_DEV_PARAMS_SENT", "FSM_BOOT_PARAMS_SENT", "FSM_EEPROM_READ_MAC_ADDR", "FSM_RESET_MAC_SENT", diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c new file mode 100644 index 000000000000..c2303599c12e --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -0,0 +1,742 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/firmware.h> +#include "rsi_mgmt.h" +#include "rsi_hal.h" +#include "rsi_sdio.h" + +/* FLASH Firmware */ +static struct ta_metadata metadata_flash_content[] = { + {"flash_content", 0x00010000}, + {"rsi/rs9113_wlan_qspi.rps", 0x00010000}, +}; + +/** + * rsi_send_data_pkt() - This function sends the recieved data packet from + * driver to device. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hdr *tmp_hdr; + struct ieee80211_tx_info *info; + struct skb_info *tx_params; + struct ieee80211_bss_conf *bss; + int status; + u8 ieee80211_size = MIN_802_11_HDR_LEN; + u8 extnd_size; + __le16 *frame_desc; + u16 seq_num; + + info = IEEE80211_SKB_CB(skb); + bss = &info->control.vif->bss_conf; + tx_params = (struct skb_info *)info->driver_data; + + if (!bss->assoc) { + status = -EINVAL; + goto err; + } + + tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; + seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4); + + extnd_size = ((uintptr_t)skb->data & 0x3); + + if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); + status = -ENOSPC; + goto err; + } + + skb_push(skb, (FRAME_DESC_SZ + extnd_size)); + frame_desc = (__le16 *)&skb->data[0]; + memset((u8 *)frame_desc, 0, FRAME_DESC_SZ); + + if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { + ieee80211_size += 2; + frame_desc[6] |= cpu_to_le16(BIT(12)); + } + + if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && + (common->secinfo.security_enable)) { + if (rsi_is_cipher_wep(common)) + ieee80211_size += 4; + else + ieee80211_size += 8; + frame_desc[6] |= cpu_to_le16(BIT(15)); + } + + frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | + (RSI_WIFI_DATA_Q << 12)); + frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8); + + if (common->min_rate != 0xffff) { + /* Send fixed rate */ + frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); + frame_desc[4] = cpu_to_le16(common->min_rate); + + if (conf_is_ht40(&common->priv->hw->conf)) + frame_desc[5] = cpu_to_le16(FULL40M_ENABLE); + + if (common->vif_info[0].sgi) { + if (common->min_rate & 0x100) /* Only MCS rates */ + frame_desc[4] |= + cpu_to_le16(ENABLE_SHORTGI_RATE); + } + + } + + frame_desc[6] |= cpu_to_le16(seq_num & 0xfff); + frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) | + (skb->priority & 0xf) | + (tx_params->sta_id << 8)); + + status = adapter->host_intf_ops->write_pkt(common->priv, skb->data, + skb->len); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", + __func__); + +err: + ++common->tx_stats.total_tx_pkt_freed[skb->priority]; + rsi_indicate_tx_status(common->priv, skb, status); + return status; +} + +/** + * rsi_send_mgmt_pkt() - This functions sends the received management packet + * from driver to device. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_send_mgmt_pkt(struct rsi_common *common, + struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hdr *wh; + struct ieee80211_tx_info *info; + struct ieee80211_bss_conf *bss; + struct ieee80211_hw *hw = adapter->hw; + struct ieee80211_conf *conf = &hw->conf; + struct skb_info *tx_params; + int status = -E2BIG; + __le16 *msg; + u8 extnd_size; + u8 vap_id = 0; + + info = IEEE80211_SKB_CB(skb); + tx_params = (struct skb_info *)info->driver_data; + extnd_size = ((uintptr_t)skb->data & 0x3); + + if (tx_params->flags & INTERNAL_MGMT_PKT) { + if ((extnd_size) > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); + dev_kfree_skb(skb); + return -ENOSPC; + } + skb_push(skb, extnd_size); + skb->data[extnd_size + 4] = extnd_size; + status = adapter->host_intf_ops->write_pkt(common->priv, + (u8 *)skb->data, + skb->len); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write the packet\n", __func__); + } + dev_kfree_skb(skb); + return status; + } + + bss = &info->control.vif->bss_conf; + wh = (struct ieee80211_hdr *)&skb->data[0]; + + if (FRAME_DESC_SZ > skb_headroom(skb)) + goto err; + + skb_push(skb, FRAME_DESC_SZ); + memset(skb->data, 0, FRAME_DESC_SZ); + msg = (__le16 *)skb->data; + + if (skb->len > MAX_MGMT_PKT_SIZE) { + rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); + goto err; + } + + msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + msg[1] = cpu_to_le16(TX_DOT11_MGMT); + msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8); + msg[3] = cpu_to_le16(RATE_INFO_ENABLE); + msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4); + + if (wh->addr1[0] & BIT(0)) + msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT); + + if (common->band == NL80211_BAND_2GHZ) + msg[4] = cpu_to_le16(RSI_11B_MODE); + else + msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE); + + if (conf_is_ht40(conf)) { + msg[4] = cpu_to_le16(0xB | RSI_11G_MODE); + msg[5] = cpu_to_le16(0x6); + } + + /* Indicate to firmware to give cfm */ + if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { + msg[1] |= cpu_to_le16(BIT(10)); + msg[7] = cpu_to_le16(PROBEREQ_CONFIRM); + common->mgmt_q_block = true; + } + + msg[7] |= cpu_to_le16(vap_id << 8); + + status = adapter->host_intf_ops->write_pkt(common->priv, (u8 *)msg, + skb->len); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); + +err: + rsi_indicate_tx_status(common->priv, skb, status); + return status; +} + +static void bl_cmd_timeout(unsigned long priv) +{ + struct rsi_hw *adapter = (struct rsi_hw *)priv; + + adapter->blcmd_timer_expired = true; + del_timer(&adapter->bl_cmd_timer); +} + +static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout) +{ + init_timer(&adapter->bl_cmd_timer); + adapter->bl_cmd_timer.data = (unsigned long)adapter; + adapter->bl_cmd_timer.function = (void *)&bl_cmd_timeout; + adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies); + + adapter->blcmd_timer_expired = false; + add_timer(&adapter->bl_cmd_timer); + + return 0; +} + +static int bl_stop_cmd_timer(struct rsi_hw *adapter) +{ + adapter->blcmd_timer_expired = false; + if (timer_pending(&adapter->bl_cmd_timer)) + del_timer(&adapter->bl_cmd_timer); + + return 0; +} + +static int bl_write_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, + u16 *cmd_resp) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + u32 regin_val = 0, regout_val = 0; + u32 regin_input = 0; + u8 output = 0; + int status; + + regin_input = (REGIN_INPUT | adapter->priv->coex_mode); + + while (!adapter->blcmd_timer_expired) { + regin_val = 0; + status = hif_ops->master_reg_read(adapter, SWBL_REGIN, + ®in_val, 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGIN reading failed..\n", + __func__, cmd); + return status; + } + mdelay(1); + if ((regin_val >> 12) != REGIN_VALID) + break; + } + if (adapter->blcmd_timer_expired) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGIN reading timed out..\n", + __func__, cmd); + return -ETIMEDOUT; + } + + rsi_dbg(INFO_ZONE, + "Issuing write to Regin val:%0x sending cmd:%0x\n", + regin_val, (cmd | regin_input << 8)); + status = hif_ops->master_reg_write(adapter, SWBL_REGIN, + (cmd | regin_input << 8), 2); + if (status < 0) + return status; + mdelay(1); + + if (cmd == LOAD_HOSTED_FW || cmd == JUMP_TO_ZERO_PC) { + /* JUMP_TO_ZERO_PC doesn't expect + * any response. So return from here + */ + return 0; + } + + while (!adapter->blcmd_timer_expired) { + regout_val = 0; + status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, + ®out_val, 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGOUT reading failed..\n", + __func__, cmd); + return status; + } + mdelay(1); + if ((regout_val >> 8) == REGOUT_VALID) + break; + } + if (adapter->blcmd_timer_expired) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGOUT reading timed out..\n", + __func__, cmd); + return status; + } + + *cmd_resp = ((u16 *)®out_val)[0] & 0xffff; + + output = ((u8 *)®out_val)[0] & 0xff; + + status = hif_ops->master_reg_write(adapter, SWBL_REGOUT, + (cmd | REGOUT_INVALID << 8), 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGOUT writing failed..\n", + __func__, cmd); + return status; + } + mdelay(1); + + if (output != exp_resp) { + rsi_dbg(ERR_ZONE, + "%s: Recvd resp %x for cmd %0x\n", + __func__, output, cmd); + return -EINVAL; + } + rsi_dbg(INFO_ZONE, + "%s: Recvd Expected resp %x for cmd %0x\n", + __func__, output, cmd); + + return 0; +} + +static int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str) +{ + u16 regout_val = 0; + u32 timeout; + int status; + + if ((cmd == EOF_REACHED) || (cmd == PING_VALID) || (cmd == PONG_VALID)) + timeout = BL_BURN_TIMEOUT; + else + timeout = BL_CMD_TIMEOUT; + + bl_start_cmd_timer(adapter, timeout); + status = bl_write_cmd(adapter, cmd, exp_resp, ®out_val); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %s (%0x) writing failed..\n", + __func__, str, cmd); + return status; + } + bl_stop_cmd_timer(adapter); + return 0; +} + +#define CHECK_SUM_OFFSET 20 +#define LEN_OFFSET 8 +#define ADDR_OFFSET 16 +static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, + u32 content_size) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + struct bl_header bl_hdr; + u32 write_addr, write_len; + int status; + + bl_hdr.flags = 0; + bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode); + bl_hdr.check_sum = cpu_to_le32( + *(u32 *)&flash_content[CHECK_SUM_OFFSET]); + bl_hdr.flash_start_address = cpu_to_le32( + *(u32 *)&flash_content[ADDR_OFFSET]); + bl_hdr.flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); + write_len = sizeof(struct bl_header); + + if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { + write_addr = PING_BUFFER_ADDRESS; + status = hif_ops->write_reg_multiple(adapter, write_addr, + (u8 *)&bl_hdr, write_len); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to load Version/CRC structure\n", + __func__); + return status; + } + } else { + write_addr = PING_BUFFER_ADDRESS >> 16; + status = hif_ops->master_access_msword(adapter, write_addr); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return status; + } + write_addr = RSI_SD_REQUEST_MASTER | + (PING_BUFFER_ADDRESS & 0xFFFF); + status = hif_ops->write_reg_multiple(adapter, write_addr, + (u8 *)&bl_hdr, write_len); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to load Version/CRC structure\n", + __func__); + return status; + } + } + return 0; +} + +static u32 read_flash_capacity(struct rsi_hw *adapter) +{ + u32 flash_sz = 0; + + if ((adapter->host_intf_ops->master_reg_read(adapter, FLASH_SIZE_ADDR, + &flash_sz, 2)) < 0) { + rsi_dbg(ERR_ZONE, + "%s: Flash size reading failed..\n", + __func__); + return 0; + } + rsi_dbg(INIT_ZONE, "Flash capacity: %d KiloBytes\n", flash_sz); + + return (flash_sz * 1024); /* Return size in kbytes */ +} + +static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + u32 block_size = adapter->block_size; + u32 cmd_addr; + u16 cmd_resp, cmd_req; + u8 *str; + int status; + + if (cmd == PING_WRITE) { + cmd_addr = PING_BUFFER_ADDRESS; + cmd_resp = PONG_AVAIL; + cmd_req = PING_VALID; + str = "PING_VALID"; + } else { + cmd_addr = PONG_BUFFER_ADDRESS; + cmd_resp = PING_AVAIL; + cmd_req = PONG_VALID; + str = "PONG_VALID"; + } + + status = hif_ops->load_data_master_write(adapter, cmd_addr, size, + block_size, addr); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Unable to write blk at addr %0x\n", + __func__, *addr); + return status; + } + + status = bl_cmd(adapter, cmd_req, cmd_resp, str); + if (status) { + bl_stop_cmd_timer(adapter); + return status; + } + return 0; +} + +static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content, + u32 content_size) +{ + u8 cmd, *temp_flash_content; + u32 temp_content_size, num_flash, index; + u32 flash_start_address; + int status; + + temp_flash_content = flash_content; + + if (content_size > MAX_FLASH_FILE_SIZE) { + rsi_dbg(ERR_ZONE, + "%s: Flash Content size is more than 400K %u\n", + __func__, MAX_FLASH_FILE_SIZE); + return -EINVAL; + } + + flash_start_address = *(u32 *)&flash_content[FLASH_START_ADDRESS]; + rsi_dbg(INFO_ZONE, "flash start address: %08x\n", flash_start_address); + + if (flash_start_address < FW_IMAGE_MIN_ADDRESS) { + rsi_dbg(ERR_ZONE, + "%s: Fw image Flash Start Address is less than 64K\n", + __func__); + return -EINVAL; + } + + if (flash_start_address % FLASH_SECTOR_SIZE) { + rsi_dbg(ERR_ZONE, + "%s: Flash Start Address is not multiple of 4K\n", + __func__); + return -EINVAL; + } + + if ((flash_start_address + content_size) > adapter->flash_capacity) { + rsi_dbg(ERR_ZONE, + "%s: Flash Content will cross max flash size\n", + __func__); + return -EINVAL; + } + + temp_content_size = content_size; + num_flash = content_size / FLASH_WRITE_CHUNK_SIZE; + + rsi_dbg(INFO_ZONE, "content_size: %d, num_flash: %d\n", + content_size, num_flash); + + for (index = 0; index <= num_flash; index++) { + rsi_dbg(INFO_ZONE, "flash index: %d\n", index); + if (index != num_flash) { + content_size = FLASH_WRITE_CHUNK_SIZE; + rsi_dbg(INFO_ZONE, "QSPI content_size:%d\n", + content_size); + } else { + content_size = + temp_content_size % FLASH_WRITE_CHUNK_SIZE; + rsi_dbg(INFO_ZONE, + "Writing last sector content_size:%d\n", + content_size); + if (!content_size) { + rsi_dbg(INFO_ZONE, "instruction size zero\n"); + break; + } + } + + if (index % 2) + cmd = PING_WRITE; + else + cmd = PONG_WRITE; + + status = ping_pong_write(adapter, cmd, flash_content, + content_size); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Unable to load %d block\n", + __func__, index); + return status; + } + + rsi_dbg(INFO_ZONE, + "%s: Successfully loaded %d instructions\n", + __func__, index); + flash_content += content_size; + } + + status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL, + "EOF_REACHED"); + if (status) { + bl_stop_cmd_timer(adapter); + return status; + } + rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n"); + return 0; +} + +static int rsi_load_firmware(struct rsi_hw *adapter) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + const struct firmware *fw_entry = NULL; + u32 regout_val = 0, content_size; + u16 tmp_regout_val = 0; + u8 *flash_content = NULL; + struct ta_metadata *metadata_p; + int status; + + bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT); + + while (!adapter->blcmd_timer_expired) { + status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, + ®out_val, 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: REGOUT read failed\n", __func__); + return status; + } + mdelay(1); + if ((regout_val >> 8) == REGOUT_VALID) + break; + } + if (adapter->blcmd_timer_expired) { + rsi_dbg(ERR_ZONE, "%s: REGOUT read timedout\n", __func__); + rsi_dbg(ERR_ZONE, + "%s: Soft boot loader not present\n", __func__); + return -ETIMEDOUT; + } + bl_stop_cmd_timer(adapter); + + rsi_dbg(INFO_ZONE, "Received Board Version Number: %x\n", + (regout_val & 0xff)); + + status = hif_ops->master_reg_write(adapter, SWBL_REGOUT, + (REGOUT_INVALID | REGOUT_INVALID << 8), + 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__); + return status; + } + mdelay(1); + + status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, + "AUTO_READ_CMD"); + if (status < 0) + return status; + + adapter->flash_capacity = read_flash_capacity(adapter); + if (adapter->flash_capacity <= 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to read flash size from EEPROM\n", + __func__); + return -EINVAL; + } + + metadata_p = &metadata_flash_content[adapter->priv->coex_mode]; + + rsi_dbg(INIT_ZONE, "%s: Loading file %s\n", __func__, metadata_p->name); + adapter->fw_file_name = metadata_p->name; + + status = request_firmware(&fw_entry, metadata_p->name, adapter->device); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n", + __func__, metadata_p->name); + return status; + } + flash_content = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + if (!flash_content) { + rsi_dbg(ERR_ZONE, "%s: Failed to copy firmware\n", __func__); + status = -EIO; + goto fail; + } + content_size = fw_entry->size; + rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", content_size); + + status = bl_write_header(adapter, flash_content, content_size); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: RPS Image header loading failed\n", + __func__); + goto fail; + } + + bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT); + status = bl_write_cmd(adapter, CHECK_CRC, CMD_PASS, &tmp_regout_val); + if (status) { + bl_stop_cmd_timer(adapter); + rsi_dbg(ERR_ZONE, + "%s: CHECK_CRC Command writing failed..\n", + __func__); + if ((tmp_regout_val & 0xff) == CMD_FAIL) { + rsi_dbg(ERR_ZONE, + "CRC Fail.. Proceeding to Upgrade mode\n"); + goto fw_upgrade; + } + } + bl_stop_cmd_timer(adapter); + + status = bl_cmd(adapter, POLLING_MODE, CMD_PASS, "POLLING_MODE"); + if (status) + goto fail; + +load_image_cmd: + status = bl_cmd(adapter, LOAD_HOSTED_FW, LOADING_INITIATED, + "LOAD_HOSTED_FW"); + if (status) + goto fail; + rsi_dbg(INFO_ZONE, "Load Image command passed..\n"); + goto success; + +fw_upgrade: + status = bl_cmd(adapter, BURN_HOSTED_FW, SEND_RPS_FILE, "FW_UPGRADE"); + if (status) + goto fail; + + rsi_dbg(INFO_ZONE, "Burn Command Pass.. Upgrading the firmware\n"); + + status = auto_fw_upgrade(adapter, flash_content, content_size); + if (status == 0) { + rsi_dbg(ERR_ZONE, "Firmware upgradation Done\n"); + goto load_image_cmd; + } + rsi_dbg(ERR_ZONE, "Firmware upgrade failed\n"); + + status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, + "AUTO_READ_MODE"); + if (status) + goto fail; + +success: + rsi_dbg(ERR_ZONE, "***** Firmware Loading successful *****\n"); + kfree(flash_content); + release_firmware(fw_entry); + return 0; + +fail: + rsi_dbg(ERR_ZONE, "##### Firmware loading failed #####\n"); + kfree(flash_content); + release_firmware(fw_entry); + return status; +} + +int rsi_hal_device_init(struct rsi_hw *adapter) +{ + struct rsi_common *common = adapter->priv; + + common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE; + common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE; + adapter->device_model = RSI_DEV_9113; + + switch (adapter->device_model) { + case RSI_DEV_9113: + if (rsi_load_firmware(adapter)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to load TA instructions\n", + __func__); + return -EINVAL; + } + break; + default: + return -EINVAL; + } + common->fsm_state = FSM_CARD_NOT_READY; + + return 0; +} +EXPORT_SYMBOL_GPL(rsi_hal_device_init); + diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 8810862ae826..f1cde0ca81f9 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -123,9 +123,16 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len) queueno = rsi_get_queueno(frame_desc, offset); length = rsi_get_length(frame_desc, offset); - extended_desc = rsi_get_extended_desc(frame_desc, offset); + + /* Extended descriptor is valid for WLAN queues only */ + if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q) + extended_desc = rsi_get_extended_desc(frame_desc, + offset); switch (queueno) { + case RSI_COEX_Q: + rsi_mgmt_pkt_recv(common, (frame_desc + offset)); + break; case RSI_WIFI_DATA_Q: skb = rsi_prepare_skb(common, (frame_desc + offset), diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index fac87c06357b..d4d365b5d2d6 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -45,10 +45,10 @@ static struct bootup_params boot_params_20 = { } }, .switch_clk_g = { - .switch_clk_info = cpu_to_le16(BIT(3)), - .bbp_lmac_clk_reg_val = cpu_to_le16(0x121), - .umac_clock_reg_config = 0x0, - .qspi_uart_clock_reg_config = 0x0 + .switch_clk_info = cpu_to_le16(0xb), + .bbp_lmac_clk_reg_val = cpu_to_le16(0x111), + .umac_clock_reg_config = cpu_to_le16(0x48), + .qspi_uart_clock_reg_config = cpu_to_le16(0x1211) } }, { @@ -106,7 +106,10 @@ static struct bootup_params boot_params_20 = { .wdt_prog_value = 0x0, .wdt_soc_rst_delay = 0x0, .dcdc_operation_mode = 0x0, - .soc_reset_wait_cnt = 0x0 + .soc_reset_wait_cnt = 0x0, + .waiting_time_at_fresh_sleep = 0x0, + .max_threshold_to_avoid_sleep = 0x0, + .beacon_resedue_alg_en = 0, }; static struct bootup_params boot_params_40 = { @@ -139,7 +142,7 @@ static struct bootup_params boot_params_40 = { .switch_clk_info = cpu_to_le16(0x09), .bbp_lmac_clk_reg_val = cpu_to_le16(0x1121), .umac_clock_reg_config = cpu_to_le16(0x48), - .qspi_uart_clock_reg_config = 0x0 + .qspi_uart_clock_reg_config = cpu_to_le16(0x1211) } }, { @@ -197,7 +200,10 @@ static struct bootup_params boot_params_40 = { .wdt_prog_value = 0x0, .wdt_soc_rst_delay = 0x0, .dcdc_operation_mode = 0x0, - .soc_reset_wait_cnt = 0x0 + .soc_reset_wait_cnt = 0x0, + .waiting_time_at_fresh_sleep = 0x0, + .max_threshold_to_avoid_sleep = 0x0, + .beacon_resedue_alg_en = 0, }; static u16 mcs[] = {13, 26, 39, 52, 78, 104, 117, 130}; @@ -218,6 +224,12 @@ static void rsi_set_default_parameters(struct rsi_common *common) common->fsm_state = FSM_CARD_NOT_READY; common->iface_down = true; common->endpoint = EP_2GHZ_20MHZ; + common->driver_mode = 1; /* End to end mode */ + common->lp_ps_handshake_mode = 0; /* Default no handShake mode*/ + common->ulp_ps_handshake_mode = 2; /* Default PKT handShake mode*/ + common->rf_power_val = 0; /* Default 1.9V */ + common->wlan_rf_power_mode = 0; + common->obm_ant_sel_val = 2; } /** @@ -389,9 +401,7 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, struct ieee80211_tx_info *info; struct skb_info *rx_params; u8 pad_bytes = msg[4]; - u8 pkt_recv; struct sk_buff *skb; - char *buffer; if (type == RX_DOT11_MGMT) { if (!adapter->sc_nvifs) @@ -412,13 +422,9 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, return -ENOMEM; } - buffer = skb_put(skb, msg_len); - - memcpy(buffer, - (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), - msg_len); - - pkt_recv = buffer[0]; + skb_put_data(skb, + (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), + msg_len); info = IEEE80211_SKB_CB(skb); rx_params = (struct skb_info *)info->driver_data; @@ -756,6 +762,53 @@ int rsi_hal_load_key(struct rsi_common *common, } /* + * This function sends the common device configuration parameters to device. + * This frame includes the useful information to make device works on + * specific operating mode. + */ +static int rsi_send_common_dev_params(struct rsi_common *common) +{ + struct sk_buff *skb; + u16 frame_len; + struct rsi_config_vals *dev_cfgs; + + frame_len = sizeof(struct rsi_config_vals); + + rsi_dbg(MGMT_TX_ZONE, "Sending common device config params\n"); + skb = dev_alloc_skb(frame_len); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Unable to allocate skb\n", __func__); + return -ENOMEM; + } + + memset(skb->data, 0, frame_len); + + dev_cfgs = (struct rsi_config_vals *)skb->data; + memset(dev_cfgs, 0, (sizeof(struct rsi_config_vals))); + + rsi_set_len_qno(&dev_cfgs->len_qno, (frame_len - FRAME_DESC_SZ), + RSI_COEX_Q); + dev_cfgs->pkt_type = COMMON_DEV_CONFIG; + + dev_cfgs->lp_ps_handshake = common->lp_ps_handshake_mode; + dev_cfgs->ulp_ps_handshake = common->ulp_ps_handshake_mode; + + dev_cfgs->unused_ulp_gpio = RSI_UNUSED_ULP_GPIO_BITMAP; + dev_cfgs->unused_soc_gpio_bitmap = + cpu_to_le32(RSI_UNUSED_SOC_GPIO_BITMAP); + + dev_cfgs->opermode = common->oper_mode; + dev_cfgs->wlan_rf_pwr_mode = common->wlan_rf_power_mode; + dev_cfgs->driver_mode = common->driver_mode; + dev_cfgs->region_code = NL80211_DFS_FCC; + dev_cfgs->antenna_sel_val = common->obm_ant_sel_val; + + skb_put(skb, frame_len); + + return rsi_send_internal_mgmt_frame(common, skb); +} + +/* * rsi_load_bootup_params() - This function send bootup params to the firmware. * @common: Pointer to the driver private structure. * @@ -1487,6 +1540,40 @@ out: return -EINVAL; } +static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg) +{ + switch (common->fsm_state) { + case FSM_CARD_NOT_READY: + rsi_dbg(INIT_ZONE, "Card ready indication from Common HAL\n"); + rsi_set_default_parameters(common); + if (rsi_send_common_dev_params(common) < 0) + return -EINVAL; + common->fsm_state = FSM_COMMON_DEV_PARAMS_SENT; + break; + case FSM_COMMON_DEV_PARAMS_SENT: + rsi_dbg(INIT_ZONE, "Card ready indication from WLAN HAL\n"); + + /* Get usb buffer status register address */ + common->priv->usb_buffer_status_reg = *(u32 *)&msg[8]; + rsi_dbg(INFO_ZONE, "USB buffer status register = %x\n", + common->priv->usb_buffer_status_reg); + + if (rsi_load_bootup_params(common)) { + common->fsm_state = FSM_CARD_NOT_READY; + return -EINVAL; + } + common->fsm_state = FSM_BOOT_PARAMS_SENT; + break; + default: + rsi_dbg(ERR_ZONE, + "%s: card ready indication in invalid state %d.\n", + __func__, common->fsm_state); + return -EINVAL; + } + + return 0; +} + /** * rsi_mgmt_pkt_recv() - This function processes the management packets * recieved from the hardware. @@ -1499,7 +1586,6 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) { s32 msg_len = (le16_to_cpu(*(__le16 *)&msg[0]) & 0x0fff); u16 msg_type = (msg[2]); - int ret; rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n", __func__, msg_len, msg_type); @@ -1509,17 +1595,7 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) } else if (msg_type == CARD_READY_IND) { rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n", __func__); - if (common->fsm_state == FSM_CARD_NOT_READY) { - rsi_set_default_parameters(common); - - ret = rsi_load_bootup_params(common); - if (ret) - return ret; - else - common->fsm_state = FSM_BOOT_PARAMS_SENT; - } else { - return -EINVAL; - } + return rsi_handle_card_ready(common, msg); } else if (msg_type == TX_STATUS_IND) { if (msg[15] == PROBEREQ_CONFIRM) { common->mgmt_q_block = false; diff --git a/drivers/net/wireless/rsi/rsi_91x_pkt.c b/drivers/net/wireless/rsi/rsi_91x_pkt.c deleted file mode 100644 index 02920c93e82d..000000000000 --- a/drivers/net/wireless/rsi/rsi_91x_pkt.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright (c) 2014 Redpine Signals Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "rsi_mgmt.h" - -/** - * rsi_send_data_pkt() - This function sends the recieved data packet from - * driver to device. - * @common: Pointer to the driver private structure. - * @skb: Pointer to the socket buffer structure. - * - * Return: status: 0 on success, -1 on failure. - */ -int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) -{ - struct rsi_hw *adapter = common->priv; - struct ieee80211_hdr *tmp_hdr; - struct ieee80211_tx_info *info; - struct skb_info *tx_params; - struct ieee80211_bss_conf *bss; - int status; - u8 ieee80211_size = MIN_802_11_HDR_LEN; - u8 extnd_size; - __le16 *frame_desc; - u16 seq_num; - - info = IEEE80211_SKB_CB(skb); - bss = &info->control.vif->bss_conf; - tx_params = (struct skb_info *)info->driver_data; - - if (!bss->assoc) { - status = -EINVAL; - goto err; - } - - tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; - seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4); - - extnd_size = ((uintptr_t)skb->data & 0x3); - - if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) { - rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); - status = -ENOSPC; - goto err; - } - - skb_push(skb, (FRAME_DESC_SZ + extnd_size)); - frame_desc = (__le16 *)&skb->data[0]; - memset((u8 *)frame_desc, 0, FRAME_DESC_SZ); - - if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { - ieee80211_size += 2; - frame_desc[6] |= cpu_to_le16(BIT(12)); - } - - if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && - (common->secinfo.security_enable)) { - if (rsi_is_cipher_wep(common)) - ieee80211_size += 4; - else - ieee80211_size += 8; - frame_desc[6] |= cpu_to_le16(BIT(15)); - } - - frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | - (RSI_WIFI_DATA_Q << 12)); - frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8); - - if (common->min_rate != 0xffff) { - /* Send fixed rate */ - frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); - frame_desc[4] = cpu_to_le16(common->min_rate); - - if (conf_is_ht40(&common->priv->hw->conf)) - frame_desc[5] = cpu_to_le16(FULL40M_ENABLE); - - if (common->vif_info[0].sgi) { - if (common->min_rate & 0x100) /* Only MCS rates */ - frame_desc[4] |= - cpu_to_le16(ENABLE_SHORTGI_RATE); - } - - } - - frame_desc[6] |= cpu_to_le16(seq_num & 0xfff); - frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) | - (skb->priority & 0xf) | - (tx_params->sta_id << 8)); - - status = adapter->host_intf_write_pkt(common->priv, - skb->data, - skb->len); - if (status) - rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", - __func__); - -err: - ++common->tx_stats.total_tx_pkt_freed[skb->priority]; - rsi_indicate_tx_status(common->priv, skb, status); - return status; -} - -/** - * rsi_send_mgmt_pkt() - This functions sends the received management packet - * from driver to device. - * @common: Pointer to the driver private structure. - * @skb: Pointer to the socket buffer structure. - * - * Return: status: 0 on success, -1 on failure. - */ -int rsi_send_mgmt_pkt(struct rsi_common *common, - struct sk_buff *skb) -{ - struct rsi_hw *adapter = common->priv; - struct ieee80211_hdr *wh; - struct ieee80211_tx_info *info; - struct ieee80211_bss_conf *bss; - struct ieee80211_hw *hw = adapter->hw; - struct ieee80211_conf *conf = &hw->conf; - struct skb_info *tx_params; - int status = -E2BIG; - __le16 *msg; - u8 extnd_size; - u8 vap_id = 0; - - info = IEEE80211_SKB_CB(skb); - tx_params = (struct skb_info *)info->driver_data; - extnd_size = ((uintptr_t)skb->data & 0x3); - - if (tx_params->flags & INTERNAL_MGMT_PKT) { - if ((extnd_size) > skb_headroom(skb)) { - rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); - dev_kfree_skb(skb); - return -ENOSPC; - } - skb_push(skb, extnd_size); - skb->data[extnd_size + 4] = extnd_size; - status = adapter->host_intf_write_pkt(common->priv, - (u8 *)skb->data, - skb->len); - if (status) { - rsi_dbg(ERR_ZONE, - "%s: Failed to write the packet\n", __func__); - } - dev_kfree_skb(skb); - return status; - } - - bss = &info->control.vif->bss_conf; - wh = (struct ieee80211_hdr *)&skb->data[0]; - - if (FRAME_DESC_SZ > skb_headroom(skb)) - goto err; - - skb_push(skb, FRAME_DESC_SZ); - memset(skb->data, 0, FRAME_DESC_SZ); - msg = (__le16 *)skb->data; - - if (skb->len > MAX_MGMT_PKT_SIZE) { - rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); - goto err; - } - - msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - msg[1] = cpu_to_le16(TX_DOT11_MGMT); - msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8); - msg[3] = cpu_to_le16(RATE_INFO_ENABLE); - msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4); - - if (wh->addr1[0] & BIT(0)) - msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT); - - if (common->band == NL80211_BAND_2GHZ) - msg[4] = cpu_to_le16(RSI_11B_MODE); - else - msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE); - - if (conf_is_ht40(conf)) { - msg[4] = cpu_to_le16(0xB | RSI_11G_MODE); - msg[5] = cpu_to_le16(0x6); - } - - /* Indicate to firmware to give cfm */ - if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { - msg[1] |= cpu_to_le16(BIT(10)); - msg[7] = cpu_to_le16(PROBEREQ_CONFIRM); - common->mgmt_q_block = true; - } - - msg[7] |= cpu_to_le16(vap_id << 8); - - status = adapter->host_intf_write_pkt(common->priv, - (u8 *)msg, - skb->len); - if (status) - rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); - -err: - rsi_indicate_tx_status(common->priv, skb, status); - return status; -} diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8428858204a6..e5ea99bb2dd8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include "rsi_sdio.h" #include "rsi_common.h" +#include "rsi_hal.h" /** * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg. @@ -138,6 +139,8 @@ static void rsi_handle_interrupt(struct sdio_func *function) { struct rsi_hw *adapter = sdio_get_drvdata(function); + if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED) + return; sdio_release_host(function); rsi_interrupt_handler(adapter); sdio_claim_host(function); @@ -365,6 +368,7 @@ static int rsi_setblocklength(struct rsi_hw *adapter, u32 length) status = sdio_set_block_size(dev->pfunction, length); dev->pfunction->max_blksize = 256; + adapter->block_size = dev->pfunction->max_blksize; rsi_dbg(INFO_ZONE, "%s: Operational blk length is %d\n", __func__, length); @@ -487,8 +491,8 @@ void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit) */ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter, u32 addr, - u32 count, - u8 *data) + u8 *data, + u16 count) { struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; @@ -518,7 +522,7 @@ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter, int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr, u8 *data, - u32 count) + u16 count) { struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; @@ -552,6 +556,182 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, return status; } +static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, + u32 base_address, + u32 instructions_sz, + u16 block_size, + u8 *ta_firmware) +{ + u32 num_blocks, offset, i; + u16 msb_address, lsb_address; + u8 temp_buf[block_size]; + int status; + + num_blocks = instructions_sz / block_size; + msb_address = base_address >> 16; + + rsi_dbg(INFO_ZONE, "ins_size: %d, num_blocks: %d\n", + instructions_sz, num_blocks); + + /* Loading DM ms word in the sdio slave */ + status = rsi_sdio_master_access_msword(adapter, msb_address); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); + return status; + } + + for (offset = 0, i = 0; i < num_blocks; i++, offset += block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + offset, block_size); + lsb_address = (u16)base_address; + status = rsi_sdio_write_register_multiple + (adapter, + lsb_address | RSI_SD_REQUEST_MASTER, + temp_buf, block_size); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: failed to write\n", __func__); + return status; + } + rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); + base_address += block_size; + + if ((base_address >> 16) != msb_address) { + msb_address += 1; + + /* Loading DM ms word in the sdio slave */ + status = rsi_sdio_master_access_msword(adapter, + msb_address); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word reg\n", + __func__); + return status; + } + } + } + + if (instructions_sz % block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + offset, + instructions_sz % block_size); + lsb_address = (u16)base_address; + status = rsi_sdio_write_register_multiple + (adapter, + lsb_address | RSI_SD_REQUEST_MASTER, + temp_buf, + instructions_sz % block_size); + if (status < 0) + return status; + rsi_dbg(INFO_ZONE, + "Written Last Block in Address 0x%x Successfully\n", + offset | RSI_SD_REQUEST_MASTER); + } + return 0; +} + +#define FLASH_SIZE_ADDR 0x04000016 +static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, + u32 *read_buf, u16 size) +{ + u32 addr_on_bus, *data; + u32 align[2] = {}; + u16 ms_addr; + int status; + + data = PTR_ALIGN(&align[0], 8); + + ms_addr = (addr >> 16); + status = rsi_sdio_master_access_msword(adapter, ms_addr); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return status; + } + addr &= 0xFFFF; + + addr_on_bus = (addr & 0xFF000000); + if ((addr_on_bus == (FLASH_SIZE_ADDR & 0xFF000000)) || + (addr_on_bus == 0x0)) + addr_on_bus = (addr & ~(0x3)); + else + addr_on_bus = addr; + + /* Bring TA out of reset */ + status = rsi_sdio_read_register_multiple + (adapter, + (addr_on_bus | RSI_SD_REQUEST_MASTER), + (u8 *)data, 4); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__); + return status; + } + if (size == 2) { + if ((addr & 0x3) == 0) + *read_buf = *data; + else + *read_buf = (*data >> 16); + *read_buf = (*read_buf & 0xFFFF); + } else if (size == 1) { + if ((addr & 0x3) == 0) + *read_buf = *data; + else if ((addr & 0x3) == 1) + *read_buf = (*data >> 8); + else if ((addr & 0x3) == 2) + *read_buf = (*data >> 16); + else + *read_buf = (*data >> 24); + *read_buf = (*read_buf & 0xFF); + } else { + *read_buf = *data; + } + + return 0; +} + +static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, + unsigned long addr, + unsigned long data, u16 size) +{ + unsigned long data1[2], *data_aligned; + int status; + + data_aligned = PTR_ALIGN(&data1[0], 8); + + if (size == 2) { + *data_aligned = ((data << 16) | (data & 0xFFFF)); + } else if (size == 1) { + u32 temp_data = data & 0xFF; + + *data_aligned = ((temp_data << 24) | (temp_data << 16) | + (temp_data << 8) | temp_data); + } else { + *data_aligned = data; + } + size = 4; + + status = rsi_sdio_master_access_msword(adapter, (addr >> 16)); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return -EIO; + } + addr = addr & 0xFFFF; + + /* Bring TA out of reset */ + status = rsi_sdio_write_register_multiple + (adapter, + (addr | RSI_SD_REQUEST_MASTER), + (u8 *)data_aligned, size); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to do AHB reg write\n", __func__); + return status; + } + return 0; +} + /** * rsi_sdio_host_intf_write_pkt() - This function writes the packet to device. * @adapter: Pointer to the adapter structure. @@ -614,8 +794,8 @@ int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, status = rsi_sdio_read_register_multiple(adapter, length, - length, /*num of bytes*/ - (u8 *)pkt); + (u8 *)pkt, + length); /*num of bytes*/ if (status) rsi_dbg(ERR_ZONE, "%s: Failed to read frame: %d\n", __func__, @@ -676,8 +856,6 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter, } sdio_release_host(pfunction); - adapter->host_intf_write_pkt = rsi_sdio_host_intf_write_pkt; - adapter->host_intf_read_pkt = rsi_sdio_host_intf_read_pkt; adapter->determine_event_timeout = rsi_sdio_determine_event_timeout; adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register; @@ -691,6 +869,17 @@ fail: return status; } +static struct rsi_host_intf_ops sdio_host_intf_ops = { + .write_pkt = rsi_sdio_host_intf_write_pkt, + .read_pkt = rsi_sdio_host_intf_read_pkt, + .master_access_msword = rsi_sdio_master_access_msword, + .read_reg_multiple = rsi_sdio_read_register_multiple, + .write_reg_multiple = rsi_sdio_write_register_multiple, + .master_reg_read = rsi_sdio_master_reg_read, + .master_reg_write = rsi_sdio_master_reg_write, + .load_data_master_write = rsi_sdio_load_data_master_write, +}; + /** * rsi_probe() - This function is called by kernel when the driver provided * Vendor and device IDs are matched. All the initialization @@ -713,31 +902,38 @@ static int rsi_probe(struct sdio_func *pfunction, __func__); return 1; } + adapter->rsi_host_intf = RSI_HOST_INTF_SDIO; + adapter->host_intf_ops = &sdio_host_intf_ops; if (rsi_init_sdio_interface(adapter, pfunction)) { rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n", __func__); goto fail; } + sdio_claim_host(pfunction); + if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { + rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); + sdio_release_host(pfunction); + goto fail; + } + sdio_release_host(pfunction); + rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); - if (rsi_sdio_device_init(adapter->priv)) { + if (rsi_hal_device_init(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); sdio_claim_host(pfunction); + sdio_release_irq(pfunction); sdio_disable_func(pfunction); sdio_release_host(pfunction); goto fail; } + rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n"); - sdio_claim_host(pfunction); - if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { - rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); - sdio_release_host(pfunction); - goto fail; + if (rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR)) { + rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); + return -EIO; } - sdio_release_host(pfunction); - rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); - return 0; fail: rsi_91x_deinit(adapter); diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 40d72312f3df..df2a63b1f15c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -27,8 +27,7 @@ * * Return: status: 0 on success, -1 on failure. */ -static int rsi_sdio_master_access_msword(struct rsi_hw *adapter, - u16 ms_word) +int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word) { u8 byte; u8 function = 0; @@ -61,171 +60,6 @@ static int rsi_sdio_master_access_msword(struct rsi_hw *adapter, } /** - * rsi_copy_to_card() - This function includes the actual funtionality of - * copying the TA firmware to the card.Basically this - * function includes opening the TA file,reading the - * TA file and writing their values in blocks of data. - * @common: Pointer to the driver private structure. - * @fw: Pointer to the firmware value to be written. - * @len: length of firmware file. - * @num_blocks: Number of blocks to be written to the card. - * - * Return: 0 on success and -1 on failure. - */ -static int rsi_copy_to_card(struct rsi_common *common, - const u8 *fw, - u32 len, - u32 num_blocks) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_sdiodev *dev = - (struct rsi_91x_sdiodev *)adapter->rsi_dev; - u32 indx, ii; - u32 block_size = dev->tx_blk_size; - u32 lsb_address; - __le32 data[] = { TA_HOLD_THREAD_VALUE, TA_SOFT_RST_CLR, - TA_PC_ZERO, TA_RELEASE_THREAD_VALUE }; - u32 address[] = { TA_HOLD_THREAD_REG, TA_SOFT_RESET_REG, - TA_TH0_PC_REG, TA_RELEASE_THREAD_REG }; - u32 base_address; - u16 msb_address; - - base_address = TA_LOAD_ADDRESS; - msb_address = base_address >> 16; - - for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { - lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); - if (rsi_sdio_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load %s blk\n", __func__, - FIRMWARE_RSI9113); - return -1; - } - rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); - base_address += block_size; - if ((base_address >> 16) != msb_address) { - msb_address += 1; - if (rsi_sdio_master_access_msword(adapter, - msb_address)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word reg\n", - __func__); - return -1; - } - } - } - - if (len % block_size) { - lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); - if (rsi_sdio_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - len % block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load f/w\n", __func__); - return -1; - } - } - rsi_dbg(INIT_ZONE, - "%s: Succesfully loaded TA instructions\n", __func__); - - if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word to common reg\n", - __func__); - return -1; - } - - for (ii = 0; ii < ARRAY_SIZE(data); ii++) { - /* Bringing TA out of reset */ - if (rsi_sdio_write_register_multiple(adapter, - (address[ii] | - RSI_SD_REQUEST_MASTER), - (u8 *)&data[ii], - 4)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to hold TA threads\n", __func__); - return -1; - } - } - - rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); - return 0; -} - -/** - * rsi_load_ta_instructions() - This function includes the actual funtionality - * of loading the TA firmware.This function also - * includes opening the TA file,reading the TA - * file and writing their value in blocks of data. - * @common: Pointer to the driver private structure. - * - * Return: status: 0 on success, -1 on failure. - */ -static int rsi_load_ta_instructions(struct rsi_common *common) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_sdiodev *dev = - (struct rsi_91x_sdiodev *)adapter->rsi_dev; - u32 len; - u32 num_blocks; - const u8 *fw; - const struct firmware *fw_entry = NULL; - u32 block_size = dev->tx_blk_size; - int status = 0; - u32 base_address; - u16 msb_address; - - if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word to common reg\n", - __func__); - return -1; - } - base_address = TA_LOAD_ADDRESS; - msb_address = (base_address >> 16); - - if (rsi_sdio_master_access_msword(adapter, msb_address)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word reg\n", __func__); - return -1; - } - - status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); - if (status < 0) { - rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", - __func__, FIRMWARE_RSI9113); - return status; - } - - /* Copy firmware into DMA-accessible memory */ - fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) { - status = -ENOMEM; - goto out; - } - len = fw_entry->size; - - if (len % 4) - len += (4 - (len % 4)); - - num_blocks = (len / block_size); - - rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); - rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - - status = rsi_copy_to_card(common, fw, len, num_blocks); - kfree(fw); - -out: - release_firmware(fw_entry); - return status; -} - -/** * rsi_process_pkt() - This Function reads rx_blocks register and figures out * the size of the rx pkt. * @common: Pointer to the driver private structure. @@ -472,28 +306,6 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) } /** - * rsi_device_init() - This Function Initializes The HAL. - * @common: Pointer to the driver private structure. - * - * Return: 0 on success, -1 on failure. - */ -int rsi_sdio_device_init(struct rsi_common *common) -{ - if (rsi_load_ta_instructions(common)) - return -1; - - if (rsi_sdio_master_access_msword(common->priv, MISC_CFG_BASE_ADDR)) { - rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", - __func__); - return -1; - } - rsi_dbg(INIT_ZONE, - "%s: Setting ms word to 0x41050000\n", __func__); - - return 0; -} - -/** * rsi_sdio_read_buffer_status_register() - This function is used to the read * buffer status register and set * relevant fields in diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index cc8deecea8cb..bcd7f454ef30 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include "rsi_usb.h" +#include "rsi_hal.h" /** * rsi_usb_card_write() - This function writes to the USB Card. @@ -141,6 +142,9 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, return 0; } +#define RSI_USB_REQ_OUT (USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE) +#define RSI_USB_REQ_IN (USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE) + /* rsi_usb_reg_read() - This function reads data from given register address. * @usbdev: Pointer to the usb_device structure. * @reg: Address of the register to be read. @@ -164,11 +168,11 @@ static int rsi_usb_reg_read(struct usb_device *usbdev, status = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_READ, - USB_TYPE_VENDOR, + RSI_USB_REQ_IN, ((reg & 0xffff0000) >> 16), (reg & 0xffff), (void *)buf, len, - HZ * 5); + USB_CTRL_GET_TIMEOUT); *value = (buf[0] | (buf[1] << 8)); if (status < 0) { @@ -211,12 +215,12 @@ static int rsi_usb_reg_write(struct usb_device *usbdev, status = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_WRITE, - USB_TYPE_VENDOR, + RSI_USB_REQ_OUT, ((reg & 0xffff0000) >> 16), (reg & 0xffff), (void *)usb_reg_buf, len, - HZ * 5); + USB_CTRL_SET_TIMEOUT); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Reg write failed with error code :%d\n", @@ -273,6 +277,46 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter) return status; } +static int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + u8 *buf; + u16 transfer; + int status; + + if (!addr) + return -EINVAL; + + buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + while (count) { + transfer = min_t(u16, count, RSI_USB_BUF_SIZE); + status = usb_control_msg(dev->usbdev, + usb_rcvctrlpipe(dev->usbdev, 0), + USB_VENDOR_REGISTER_READ, + RSI_USB_REQ_IN, + ((addr & 0xffff0000) >> 16), + (addr & 0xffff), (void *)buf, + transfer, USB_CTRL_GET_TIMEOUT); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "Reg read failed with error code :%d\n", + status); + kfree(buf); + return status; + } + memcpy(data, buf, transfer); + count -= transfer; + data += transfer; + addr += transfer; + } + kfree(buf); + return 0; +} + /** * rsi_usb_write_register_multiple() - This function writes multiple bytes of * information to multiple registers. @@ -283,41 +327,40 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter) * * Return: status: 0 on success, a negative error code on failure. */ -int rsi_usb_write_register_multiple(struct rsi_hw *adapter, - u32 addr, - u8 *data, - u32 count) +static int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; u8 *buf; - u8 transfer; + u16 transfer; int status = 0; - buf = kzalloc(4096, GFP_KERNEL); + buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; while (count) { - transfer = (u8)(min_t(u32, count, 4096)); + transfer = min_t(u16, count, RSI_USB_BUF_SIZE); memcpy(buf, data, transfer); status = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), USB_VENDOR_REGISTER_WRITE, - USB_TYPE_VENDOR, + RSI_USB_REQ_OUT, ((addr & 0xffff0000) >> 16), (addr & 0xffff), (void *)buf, transfer, - HZ * 5); + USB_CTRL_SET_TIMEOUT); if (status < 0) { rsi_dbg(ERR_ZONE, "Reg write failed with error code :%d\n", status); - } else { - count -= transfer; - data += transfer; - addr += transfer; + kfree(buf); + return status; } + count -= transfer; + data += transfer; + addr += transfer; } kfree(buf); @@ -348,6 +391,77 @@ static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, len); } +static int rsi_usb_master_reg_read(struct rsi_hw *adapter, u32 reg, + u32 *value, u16 len) +{ + struct usb_device *usbdev = + ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; + + return rsi_usb_reg_read(usbdev, reg, (u16 *)value, len); +} + +static int rsi_usb_master_reg_write(struct rsi_hw *adapter, + unsigned long reg, + unsigned long value, u16 len) +{ + struct usb_device *usbdev = + ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; + + return rsi_usb_reg_write(usbdev, reg, value, len); +} + +static int rsi_usb_load_data_master_write(struct rsi_hw *adapter, + u32 base_address, + u32 instructions_sz, u16 block_size, + u8 *ta_firmware) +{ + u16 num_blocks; + u32 cur_indx, i; + u8 temp_buf[256]; + int status; + + num_blocks = instructions_sz / block_size; + rsi_dbg(INFO_ZONE, "num_blocks: %d\n", num_blocks); + + for (cur_indx = 0, i = 0; i < num_blocks; i++, cur_indx += block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + cur_indx, block_size); + status = rsi_usb_write_register_multiple(adapter, base_address, + (u8 *)(temp_buf), + block_size); + if (status < 0) + return status; + + rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); + base_address += block_size; + } + + if (instructions_sz % block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + cur_indx, + instructions_sz % block_size); + status = rsi_usb_write_register_multiple + (adapter, base_address, + (u8 *)temp_buf, + instructions_sz % block_size); + if (status < 0) + return status; + rsi_dbg(INFO_ZONE, + "Written Last Block in Address 0x%x Successfully\n", + cur_indx); + } + return 0; +} + +static struct rsi_host_intf_ops usb_host_intf_ops = { + .write_pkt = rsi_usb_host_intf_write_pkt, + .read_reg_multiple = rsi_usb_read_register_multiple, + .write_reg_multiple = rsi_usb_write_register_multiple, + .master_reg_read = rsi_usb_master_reg_read, + .master_reg_write = rsi_usb_master_reg_write, + .load_data_master_write = rsi_usb_load_data_master_write, +}; + /** * rsi_deinit_usb_interface() - This function deinitializes the usb interface. * @adapter: Pointer to the adapter structure. @@ -410,12 +524,14 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, } rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt; rsi_dev->tx_blk_size = 252; + adapter->block_size = rsi_dev->tx_blk_size; /* Initializing function callbacks */ adapter->rx_urb_submit = rsi_rx_urb_submit; - adapter->host_intf_write_pkt = rsi_usb_host_intf_write_pkt; adapter->check_hw_queue_status = rsi_usb_check_queue_status; adapter->determine_event_timeout = rsi_usb_event_timeout; + adapter->rsi_host_intf = RSI_HOST_INTF_USB; + adapter->host_intf_ops = &usb_host_intf_ops; rsi_init_event(&rsi_dev->rx_thread.event); status = rsi_create_kthread(common, &rsi_dev->rx_thread, @@ -467,6 +583,7 @@ static int rsi_probe(struct usb_interface *pfunction, __func__); return -ENOMEM; } + adapter->rsi_host_intf = RSI_HOST_INTF_USB; status = rsi_init_usb_interface(adapter, pfunction); if (status) { @@ -480,25 +597,20 @@ static int rsi_probe(struct usb_interface *pfunction, dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2); - if (status) + if (status < 0) goto err1; else fw_status &= 1; if (!fw_status) { - status = rsi_usb_device_init(adapter->priv); + rsi_dbg(INIT_ZONE, "Loading firmware...\n"); + status = rsi_hal_device_init(adapter); if (status) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); goto err1; } - - status = rsi_usb_reg_write(dev->usbdev, - USB_INTERNAL_REG_1, - RSI_USB_READY_MAGIC_NUM, 1); - if (status) - goto err1; - rsi_dbg(INIT_ZONE, "%s: Performed device init\n", __func__); + rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__); } status = rsi_rx_urb_submit(adapter); @@ -554,6 +666,7 @@ static const struct usb_device_id rsi_dev_table[] = { { USB_DEVICE(0x041B, 0x0301) }, { USB_DEVICE(0x041B, 0x0201) }, { USB_DEVICE(0x041B, 0x9330) }, + { USB_DEVICE(0x1618, 0x9113) }, { /* Blank */}, }; diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index de4900862836..d3e0a07604a6 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -19,67 +19,6 @@ #include "rsi_usb.h" /** - * rsi_copy_to_card() - This function includes the actual funtionality of - * copying the TA firmware to the card.Basically this - * function includes opening the TA file,reading the TA - * file and writing their values in blocks of data. - * @common: Pointer to the driver private structure. - * @fw: Pointer to the firmware value to be written. - * @len: length of firmware file. - * @num_blocks: Number of blocks to be written to the card. - * - * Return: 0 on success and -1 on failure. - */ -static int rsi_copy_to_card(struct rsi_common *common, - const u8 *fw, - u32 len, - u32 num_blocks) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; - u32 indx, ii; - u32 block_size = dev->tx_blk_size; - u32 lsb_address; - u32 base_address; - - base_address = TA_LOAD_ADDRESS; - - for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { - lsb_address = base_address; - if (rsi_usb_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load %s blk\n", __func__, - FIRMWARE_RSI9113); - return -EIO; - } - rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); - base_address += block_size; - } - - if (len % block_size) { - lsb_address = base_address; - if (rsi_usb_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - len % block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load %s blk\n", __func__, - FIRMWARE_RSI9113); - return -EIO; - } - } - rsi_dbg(INIT_ZONE, - "%s: Succesfully loaded %s instructions\n", __func__, - FIRMWARE_RSI9113); - - rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); - return 0; -} - -/** * rsi_usb_rx_thread() - This is a kernel thread to receive the packets from * the USB device. * @common: Pointer to the driver private structure. @@ -119,67 +58,3 @@ out: complete_and_exit(&dev->rx_thread.completion, 0); } - -/** - * rsi_load_ta_instructions() - This function includes the actual funtionality - * of loading the TA firmware.This function also - * includes opening the TA file,reading the TA - * file and writing their value in blocks of data. - * @common: Pointer to the driver private structure. - * - * Return: status: 0 on success, -1 on failure. - */ -static int rsi_load_ta_instructions(struct rsi_common *common) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; - const struct firmware *fw_entry = NULL; - u32 block_size = dev->tx_blk_size; - const u8 *fw; - u32 num_blocks, len; - int status = 0; - - status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); - if (status < 0) { - rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", - __func__, FIRMWARE_RSI9113); - return status; - } - - /* Copy firmware into DMA-accessible memory */ - fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) { - status = -ENOMEM; - goto out; - } - len = fw_entry->size; - - if (len % 4) - len += (4 - (len % 4)); - - num_blocks = (len / block_size); - - rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); - rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - - status = rsi_copy_to_card(common, fw, len, num_blocks); - kfree(fw); - -out: - release_firmware(fw_entry); - return status; -} - -/** - * rsi_device_init() - This Function Initializes The HAL. - * @common: Pointer to the driver private structure. - * - * Return: 0 on success, -1 on failure. - */ -int rsi_usb_device_init(struct rsi_common *common) -{ - if (rsi_load_ta_instructions(common)) - return -EIO; - - return 0; - } diff --git a/drivers/net/wireless/rsi/rsi_boot_params.h b/drivers/net/wireless/rsi/rsi_boot_params.h index 5e2721f7909c..238ee96434ec 100644 --- a/drivers/net/wireless/rsi/rsi_boot_params.h +++ b/drivers/net/wireless/rsi/rsi_boot_params.h @@ -24,19 +24,19 @@ #define WIFI_AFEPLL_CONFIGS BIT(7) #define WIFI_SWITCH_CLK_CONFIGS BIT(8) -#define TA_PLL_M_VAL_20 8 -#define TA_PLL_N_VAL_20 1 +#define TA_PLL_M_VAL_20 9 +#define TA_PLL_N_VAL_20 0 #define TA_PLL_P_VAL_20 4 #define PLL960_M_VAL_20 0x14 #define PLL960_N_VAL_20 0 #define PLL960_P_VAL_20 5 -#define UMAC_CLK_40MHZ 40 +#define UMAC_CLK_40MHZ 80 -#define TA_PLL_M_VAL_40 46 -#define TA_PLL_N_VAL_40 3 -#define TA_PLL_P_VAL_40 3 +#define TA_PLL_M_VAL_40 9 +#define TA_PLL_N_VAL_40 0 +#define TA_PLL_P_VAL_40 4 #define PLL960_M_VAL_40 0x14 #define PLL960_N_VAL_40 0 @@ -122,5 +122,8 @@ struct bootup_params { /* dcdc modes configs */ __le32 dcdc_operation_mode; __le32 soc_reset_wait_cnt; + __le32 waiting_time_at_fresh_sleep; + __le32 max_threshold_to_avoid_sleep; + u8 beacon_resedue_alg_en; } __packed; #endif diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index d3fbe33d2324..44349696f5de 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -20,8 +20,7 @@ #include <linux/kthread.h> #define EVENT_WAIT_FOREVER 0 -#define TA_LOAD_ADDRESS 0x00 -#define FIRMWARE_RSI9113 "rsi_91x.fw" +#define FIRMWARE_RSI9113 "rs9113_wlan_qspi.rps" #define QUEUE_NOT_FULL 1 #define QUEUE_FULL 0 diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h new file mode 100644 index 000000000000..902dc540849c --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2017 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_HAL_H__ +#define __RSI_HAL_H__ + +#define FLASH_WRITE_CHUNK_SIZE (4 * 1024) +#define FLASH_SECTOR_SIZE (4 * 1024) + +#define FLASH_SIZE_ADDR 0x04000016 +#define PING_BUFFER_ADDRESS 0x19000 +#define PONG_BUFFER_ADDRESS 0x1a000 +#define SWBL_REGIN 0x41050034 +#define SWBL_REGOUT 0x4105003c +#define PING_WRITE 0x1 +#define PONG_WRITE 0x2 + +#define BL_CMD_TIMEOUT 2000 +#define BL_BURN_TIMEOUT (50 * 1000) + +#define REGIN_VALID 0xA +#define REGIN_INPUT 0xA0 +#define REGOUT_VALID 0xAB +#define REGOUT_INVALID (~0xAB) +#define CMD_PASS 0xAA +#define CMD_FAIL 0xCC + +#define LOAD_HOSTED_FW 'A' +#define BURN_HOSTED_FW 'B' +#define PING_VALID 'I' +#define PONG_VALID 'O' +#define PING_AVAIL 'I' +#define PONG_AVAIL 'O' +#define EOF_REACHED 'E' +#define CHECK_CRC 'K' +#define POLLING_MODE 'P' +#define CONFIG_AUTO_READ_MODE 'R' +#define JUMP_TO_ZERO_PC 'J' +#define FW_LOADING_SUCCESSFUL 'S' +#define LOADING_INITIATED '1' + +/* Boot loader commands */ +#define SEND_RPS_FILE '2' + +#define FW_IMAGE_MIN_ADDRESS (68 * 1024) +#define MAX_FLASH_FILE_SIZE (400 * 1024) //400K +#define FLASH_START_ADDRESS 16 + +#define COMMON_HAL_CARD_READY_IND 0x0 + +#define COMMAN_HAL_WAIT_FOR_CARD_READY 1 + +#define RSI_DEV_OPMODE_WIFI_ALONE 1 +#define RSI_DEV_COEX_MODE_WIFI_ALONE 1 + +struct bl_header { + __le32 flags; + __le32 image_no; + __le32 check_sum; + __le32 flash_start_address; + __le32 flash_len; +} __packed; + +struct ta_metadata { + char *name; + unsigned int address; +}; + +int rsi_hal_device_init(struct rsi_hw *adapter); + +#endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 1d5904bc2c74..f3985250b593 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -31,13 +31,17 @@ #define FSM_ZONE BIT(7) /* For State Machine Msgs */ #define ISR_ZONE BIT(8) /* For Interrupt Msgs */ -#define FSM_CARD_NOT_READY 0 -#define FSM_BOOT_PARAMS_SENT 1 -#define FSM_EEPROM_READ_MAC_ADDR 2 -#define FSM_RESET_MAC_SENT 3 -#define FSM_RADIO_CAPS_SENT 4 -#define FSM_BB_RF_PROG_SENT 5 -#define FSM_MAC_INIT_DONE 6 +enum RSI_FSM_STATES { + FSM_FW_NOT_LOADED, + FSM_CARD_NOT_READY, + FSM_COMMON_DEV_PARAMS_SENT, + FSM_BOOT_PARAMS_SENT, + FSM_EEPROM_READ_MAC_ADDR, + FSM_RESET_MAC_SENT, + FSM_RADIO_CAPS_SENT, + FSM_BB_RF_PROG_SENT, + FSM_MAC_INIT_DONE +}; extern u32 rsi_zone_enabled; extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); @@ -60,6 +64,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define MAX_CONTINUOUS_VI_PKTS 4 /* Queue information */ +#define RSI_COEX_Q 0x0 #define RSI_WIFI_MGMT_Q 0x4 #define RSI_WIFI_DATA_Q 0x5 #define IEEE80211_MGMT_FRAME 0x00 @@ -82,6 +87,8 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); ((_q) == VI_Q) ? IEEE80211_AC_VI : \ IEEE80211_AC_VO) +#define RSI_DEV_9113 1 + struct version_info { u16 major; u16 minor; @@ -204,13 +211,26 @@ struct rsi_common { struct cqm_info cqm_info; bool hw_data_qs_blocked; - + u8 driver_mode; + u8 coex_mode; + u16 oper_mode; + u8 lp_ps_handshake_mode; + u8 ulp_ps_handshake_mode; + u8 rf_power_val; + u8 wlan_rf_power_mode; + u8 obm_ant_sel_val; int tx_power; u8 ant_in_use; }; +enum host_intf { + RSI_HOST_INTF_SDIO = 0, + RSI_HOST_INTF_USB +}; + struct rsi_hw { struct rsi_common *priv; + u8 device_model; struct ieee80211_hw *hw; struct ieee80211_vif *vifs[RSI_MAX_VIFS]; struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES]; @@ -219,16 +239,40 @@ struct rsi_hw { struct device *device; u8 sc_nvifs; + enum host_intf rsi_host_intf; + u16 block_size; + u32 usb_buffer_status_reg; #ifdef CONFIG_RSI_DEBUGFS struct rsi_debugfs *dfsentry; u8 num_debugfs_entries; #endif + char *fw_file_name; + struct timer_list bl_cmd_timer; + bool blcmd_timer_expired; + u32 flash_capacity; u8 dfs_region; void *rsi_dev; - int (*host_intf_read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); - int (*host_intf_write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + struct rsi_host_intf_ops *host_intf_ops; int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num); int (*rx_urb_submit)(struct rsi_hw *adapter); int (*determine_event_timeout)(struct rsi_hw *adapter); }; + +struct rsi_host_intf_ops { + int (*read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + int (*write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + int (*master_access_msword)(struct rsi_hw *adapter, u16 ms_word); + int (*read_reg_multiple)(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count); + int (*write_reg_multiple)(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count); + int (*master_reg_read)(struct rsi_hw *adapter, u32 addr, + u32 *read_buf, u16 size); + int (*master_reg_write)(struct rsi_hw *adapter, + unsigned long addr, unsigned long data, + u16 size); + int (*load_data_master_write)(struct rsi_hw *adapter, u32 addr, + u32 instructions_size, u16 block_size, + u8 *fw); +}; #endif diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index dfbf7a50269b..dcb6db728cbd 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -205,6 +205,7 @@ enum cmd_frame_type { CW_MODE_REQ, PER_CMD_PKT, ANT_SEL_FRAME = 0x20, + COMMON_DEV_CONFIG = 0x28, RADIO_PARAMS_UPDATE = 0x29 }; @@ -282,6 +283,76 @@ struct rsi_radio_caps { __le16 preamble_type; } __packed; +/* ULP GPIO flags */ +#define RSI_GPIO_MOTION_SENSOR_ULP_WAKEUP BIT(0) +#define RSI_GPIO_SLEEP_IND_FROM_DEVICE BIT(1) +#define RSI_GPIO_2_ULP BIT(2) +#define RSI_GPIO_PUSH_BUTTON_ULP_WAKEUP BIT(3) + +/* SOC GPIO flags */ +#define RSI_GPIO_0_PSPI_CSN_0 BIT(0) +#define RSI_GPIO_1_PSPI_CSN_1 BIT(1) +#define RSI_GPIO_2_HOST_WAKEUP_INTR BIT(2) +#define RSI_GPIO_3_PSPI_DATA_0 BIT(3) +#define RSI_GPIO_4_PSPI_DATA_1 BIT(4) +#define RSI_GPIO_5_PSPI_DATA_2 BIT(5) +#define RSI_GPIO_6_PSPI_DATA_3 BIT(6) +#define RSI_GPIO_7_I2C_SCL BIT(7) +#define RSI_GPIO_8_I2C_SDA BIT(8) +#define RSI_GPIO_9_UART1_RX BIT(9) +#define RSI_GPIO_10_UART1_TX BIT(10) +#define RSI_GPIO_11_UART1_RTS_I2S_CLK BIT(11) +#define RSI_GPIO_12_UART1_CTS_I2S_WS BIT(12) +#define RSI_GPIO_13_DBG_UART_RX_I2S_DIN BIT(13) +#define RSI_GPIO_14_DBG_UART_RX_I2S_DOUT BIT(14) +#define RSI_GPIO_15_LP_WAKEUP_BOOT_BYPASS BIT(15) +#define RSI_GPIO_16_LED_0 BIT(16) +#define RSI_GPIO_17_BTCOEX_WLAN_ACT_EXT_ANT_SEL BIT(17) +#define RSI_GPIO_18_BTCOEX_BT_PRIO_EXT_ANT_SEL BIT(18) +#define RSI_GPIO_19_BTCOEX_BT_ACT_EXT_ON_OFF BIT(19) +#define RSI_GPIO_20_RF_RESET BIT(20) +#define RSI_GPIO_21_SLEEP_IND_FROM_DEVICE BIT(21) + +#define RSI_UNUSED_SOC_GPIO_BITMAP (RSI_GPIO_9_UART1_RX | \ + RSI_GPIO_10_UART1_TX | \ + RSI_GPIO_11_UART1_RTS_I2S_CLK | \ + RSI_GPIO_12_UART1_CTS_I2S_WS | \ + RSI_GPIO_13_DBG_UART_RX_I2S_DIN | \ + RSI_GPIO_14_DBG_UART_RX_I2S_DOUT | \ + RSI_GPIO_15_LP_WAKEUP_BOOT_BYPASS | \ + RSI_GPIO_17_BTCOEX_WLAN_ACT_EXT_ANT_SEL | \ + RSI_GPIO_18_BTCOEX_BT_PRIO_EXT_ANT_SEL | \ + RSI_GPIO_19_BTCOEX_BT_ACT_EXT_ON_OFF | \ + RSI_GPIO_21_SLEEP_IND_FROM_DEVICE) + +#define RSI_UNUSED_ULP_GPIO_BITMAP (RSI_GPIO_MOTION_SENSOR_ULP_WAKEUP | \ + RSI_GPIO_SLEEP_IND_FROM_DEVICE | \ + RSI_GPIO_2_ULP | \ + RSI_GPIO_PUSH_BUTTON_ULP_WAKEUP); +struct rsi_config_vals { + __le16 len_qno; + u8 pkt_type; + u8 misc_flags; + __le16 reserved1[6]; + u8 lp_ps_handshake; + u8 ulp_ps_handshake; + u8 sleep_config_params; /* 0 for no handshake, + * 1 for GPIO based handshake, + * 2 packet handshake + */ + u8 unused_ulp_gpio; + __le32 unused_soc_gpio_bitmap; + u8 ext_pa_or_bt_coex_en; + u8 opermode; + u8 wlan_rf_pwr_mode; + u8 bt_rf_pwr_mode; + u8 zigbee_rf_pwr_mode; + u8 driver_mode; + u8 region_code; + u8 antenna_sel_val; + u8 reserved2[16]; +} __packed; + static inline u32 rsi_get_queueno(u8 *addr, u16 offset) { return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12; @@ -307,6 +378,11 @@ static inline u8 rsi_get_channel(u8 *addr) return *(char *)(addr + 15); } +static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno) +{ + *addr = cpu_to_le16(len | ((qno & 7) << 12)); +} + int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg); int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, u8 vap_status); diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index c7e8f2be7901..9fb73f68282a 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -110,19 +110,19 @@ struct rsi_91x_sdiodev { u8 sdio_clock_speed; u32 cardcapability; u8 prev_desc[16]; - u32 tx_blk_size; + u16 tx_blk_size; u8 write_fail; }; void rsi_interrupt_handler(struct rsi_hw *adapter); int rsi_init_sdio_slave_regs(struct rsi_hw *adapter); -int rsi_sdio_device_init(struct rsi_common *common); int rsi_sdio_read_register(struct rsi_hw *adapter, u32 addr, u8 *data); int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length); int rsi_sdio_write_register(struct rsi_hw *adapter, u8 function, u32 addr, u8 *data); int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr, - u8 *data, u32 count); + u8 *data, u16 count); +int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word); void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num); diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index ebea0c411ead..59513ac61fb3 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -35,6 +35,8 @@ #define MGMT_EP 1 #define DATA_EP 2 +#define RSI_USB_BUF_SIZE 4096 + struct rsi_91x_usbdev { struct rsi_thread rx_thread; u8 endpoint; @@ -61,8 +63,5 @@ static inline int rsi_usb_event_timeout(struct rsi_hw *adapter) return EVENT_WAIT_FOREVER; } -int rsi_usb_device_init(struct rsi_common *common); -int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, - u8 *data, u32 count); void rsi_usb_rx_thread(struct rsi_common *common); #endif diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c index 709f56e5ad87..1037ec62659d 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c +++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c @@ -266,7 +266,7 @@ static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend) return ret; } -static struct hwbus_ops cw1200_sdio_hwbus_ops = { +static const struct hwbus_ops cw1200_sdio_hwbus_ops = { .hwbus_memcpy_fromio = cw1200_sdio_memcpy_fromio, .hwbus_memcpy_toio = cw1200_sdio_memcpy_toio, .lock = cw1200_sdio_lock, diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index 63f95e9c2992..412fb6e49aed 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -352,7 +352,7 @@ static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend) return irq_set_irq_wake(self->func->irq, suspend); } -static struct hwbus_ops cw1200_spi_hwbus_ops = { +static const struct hwbus_ops cw1200_spi_hwbus_ops = { .hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio, .hwbus_memcpy_toio = cw1200_spi_memcpy_toio, .lock = cw1200_spi_lock, diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index 0a0ff7e31f5b..cc2ce60f4f09 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -84,7 +84,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, return -ENOMEM; if (req->ie_len) - memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len); + skb_put_data(frame.skb, req->ie, req->ie_len); /* will be unlocked in cw1200_scan_work() */ down(&priv->scan.lock); diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index cd63ffef025a..e9050b41157a 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -574,7 +574,7 @@ cw1200_tx_h_wsm(struct cw1200_common *priv, return NULL; } - wsm = (struct wsm_tx *)skb_push(t->skb, sizeof(struct wsm_tx)); + wsm = skb_push(t->skb, sizeof(struct wsm_tx)); t->txpriv.offset += sizeof(struct wsm_tx); memset(wsm, 0, sizeof(*wsm)); wsm->hdr.len = __cpu_to_le16(t->skb->len); diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index bbf7604889b7..08f0477f78d9 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1036,7 +1036,7 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, goto out_idle; } if (req->ie_len) - memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); + skb_put_data(skb, req->ie, req->ie_len); ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, skb->len); diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c index 81de83c6fcf6..de2fa6705574 100644 --- a/drivers/net/wireless/ti/wl1251/tx.c +++ b/drivers/net/wireless/ti/wl1251/tx.c @@ -161,8 +161,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, return id; fc = *(u16 *)skb->data; - tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, - sizeof(*tx_hdr)); + tx_hdr = skb_push(skb, sizeof(*tx_hdr)); tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); rate = ieee80211_get_tx_rate(wl->hw, control); diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index d1aa3eee0e81..0cf3b4013dd6 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -793,9 +793,13 @@ static int wl18xx_set_clk(struct wl1271 *wl) ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2, (wl18xx_clk_table[clk_freq].p >> 16) & PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK); + if (ret < 0) + goto out; } else { ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN, PLLSH_WCS_PLL_SWALLOW_EN_VAL2); + if (ret < 0) + goto out; } /* choose WCS PLL */ @@ -819,8 +823,6 @@ static int wl18xx_set_clk(struct wl1271 *wl) /* reset the swallowing logic */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN, PLLSH_COEX_PLL_SWALLOW_EN_VAL2); - if (ret < 0) - goto out; out: return ret; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 7f4da727bb7b..2bfc12fdc929 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1156,9 +1156,9 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, goto out; } if (ie0_len) - memcpy(skb_put(skb, ie0_len), ie0, ie0_len); + skb_put_data(skb, ie0, ie0_len); if (ie1_len) - memcpy(skb_put(skb, ie1_len), ie1, ie1_len); + skb_put_data(skb, ie1, ie1_len); if (sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { @@ -1233,8 +1233,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); - tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); - memset(tmpl, 0, sizeof(*tmpl)); + tmpl = skb_put_zero(skb, sizeof(*tmpl)); /* llc layer */ memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); @@ -1283,7 +1282,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); /* mac80211 header */ - hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); + hdr = skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; if (wlvif->sta.qos) diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index de7e2a5fdffa..a2cb408be8aa 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -1149,15 +1149,9 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf, part.mem.start = *ppos; part.mem.size = bytes; - buf = kmalloc(bytes, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = copy_from_user(buf, user_buf, bytes); - if (ret) { - ret = -EFAULT; - goto err_out; - } + buf = memdup_user(user_buf, bytes); + if (IS_ERR(buf)) + return PTR_ERR(buf); mutex_lock(&wl->mutex); @@ -1197,7 +1191,6 @@ skip_write: if (ret == 0) *ppos += bytes; -err_out: kfree(buf); return ((ret == 0) ? bytes : ret); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 382ec15ec1af..60aaa850fbd1 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1308,13 +1308,12 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); - hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); - memset(hdr, 0, sizeof(*hdr)); + hdr = skb_put_zero(skb, sizeof(*hdr)); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS); - memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); + skb_put_zero(skb, dummy_packet_size); /* Dummy packets require the TID to be management */ skb->priority = WL1271_TID_MGMT; diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 52a55f9acd80..0f15696195f8 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -117,7 +117,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; - u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = 0, offset_to_data = 0; @@ -174,15 +173,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); - buf = skb_put(skb, pkt_data_len); - /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ - memcpy(buf, data + sizeof(*desc), pkt_data_len); + skb_put_data(skb, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) skb_pull(skb, RX_BUF_ALIGN); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 287023ef4a78..2fb38717346f 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -237,6 +237,7 @@ static const struct of_device_id wlcore_sdio_of_match_table[] = { { .compatible = "ti,wl1273", .data = &wl127x_data }, { .compatible = "ti,wl1281", .data = &wl128x_data }, { .compatible = "ti,wl1283", .data = &wl128x_data }, + { .compatible = "ti,wl1285", .data = &wl128x_data }, { .compatible = "ti,wl1801", .data = &wl18xx_data }, { .compatible = "ti,wl1805", .data = &wl18xx_data }, { .compatible = "ti,wl1807", .data = &wl18xx_data }, diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index f949ad2bd898..fdabb9242cca 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -70,10 +70,10 @@ #define WSPI_MAX_CHUNK_SIZE 4092 /* - * wl18xx driver aggregation buffer size is (13 * PAGE_SIZE) compared to - * (4 * PAGE_SIZE) for wl12xx, so use the larger buffer needed for wl18xx + * wl18xx driver aggregation buffer size is (13 * 4K) compared to + * (4 * 4K) for wl12xx, so use the larger buffer needed for wl18xx */ -#define SPI_AGGR_BUFFER_SIZE (13 * PAGE_SIZE) +#define SPI_AGGR_BUFFER_SIZE (13 * SZ_4K) /* Maximum number of SPI write chunks */ #define WSPI_MAX_NUM_OF_CHUNKS \ @@ -366,17 +366,14 @@ static int __wl12xx_spi_raw_write(struct device *child, int addr, static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, void *buf, size_t len, bool fixed) { - int ret; - /* The ELP wakeup write may fail the first time due to internal * hardware latency. It is safer to send the wakeup command twice to * avoid unexpected failures. */ if (addr == HW_ACCESS_ELP_CTRL_REG) - ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed); - ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed); + __wl12xx_spi_raw_write(child, addr, buf, len, fixed); - return ret; + return __wl12xx_spi_raw_write(child, addr, buf, len, fixed); } /** @@ -433,6 +430,7 @@ static const struct of_device_id wlcore_spi_of_match_table[] = { { .compatible = "ti,wl1273", .data = &wl127x_data}, { .compatible = "ti,wl1281", .data = &wl128x_data}, { .compatible = "ti,wl1283", .data = &wl128x_data}, + { .compatible = "ti,wl1285", .data = &wl128x_data}, { .compatible = "ti,wl1801", .data = &wl18xx_data}, { .compatible = "ti,wl1805", .data = &wl18xx_data}, { .compatible = "ti,wl1807", .data = &wl18xx_data}, diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index c1b8e4e9d70b..a3f5e9ca492a 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -223,8 +223,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks); if (total_blocks <= wl->tx_blocks_available) { - desc = (struct wl1271_tx_hw_descr *)skb_push( - skb, total_len - skb->len); + desc = skb_push(skb, total_len - skb->len); wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks, spare_blocks); diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c index de7ff395977a..7f586d76cf17 100644 --- a/drivers/net/wireless/zydas/zd1201.c +++ b/drivers/net/wireless/zydas/zd1201.c @@ -326,13 +326,13 @@ static void zd1201_usbrx(struct urb *urb) if (!(skb = dev_alloc_skb(datalen+24))) goto resubmit; - memcpy(skb_put(skb, 2), &data[datalen-16], 2); - memcpy(skb_put(skb, 2), &data[datalen-2], 2); - memcpy(skb_put(skb, 6), &data[datalen-14], 6); - memcpy(skb_put(skb, 6), &data[datalen-22], 6); - memcpy(skb_put(skb, 6), &data[datalen-8], 6); - memcpy(skb_put(skb, 2), &data[datalen-24], 2); - memcpy(skb_put(skb, len), data, len); + skb_put_data(skb, &data[datalen - 16], 2); + skb_put_data(skb, &data[datalen - 2], 2); + skb_put_data(skb, &data[datalen - 14], 6); + skb_put_data(skb, &data[datalen - 22], 6); + skb_put_data(skb, &data[datalen - 8], 6); + skb_put_data(skb, &data[datalen - 24], 2); + skb_put_data(skb, data, len); skb->protocol = eth_type_trans(skb, zd->dev); zd->dev->stats.rx_packets++; zd->dev->stats.rx_bytes += skb->len; @@ -359,9 +359,9 @@ static void zd1201_usbrx(struct urb *urb) frag->skb = skb; frag->seq = seq & IEEE80211_SCTL_SEQ; skb_reserve(skb, 2); - memcpy(skb_put(skb, 12), &data[datalen-14], 12); - memcpy(skb_put(skb, 2), &data[6], 2); - memcpy(skb_put(skb, len), data+8, len); + skb_put_data(skb, &data[datalen - 14], 12); + skb_put_data(skb, &data[6], 2); + skb_put_data(skb, data + 8, len); hlist_add_head(&frag->fnode, &zd->fraglist); goto resubmit; } @@ -385,9 +385,9 @@ static void zd1201_usbrx(struct urb *urb) if (!skb) goto resubmit; skb_reserve(skb, 2); - memcpy(skb_put(skb, 12), &data[datalen-14], 12); - memcpy(skb_put(skb, 2), &data[6], 2); - memcpy(skb_put(skb, len), data+8, len); + skb_put_data(skb, &data[datalen - 14], 12); + skb_put_data(skb, &data[6], 2); + skb_put_data(skb, data + 8, len); } skb->protocol = eth_type_trans(skb, zd->dev); zd->dev->stats.rx_packets++; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index fe6517a621b0..b785742bfd9e 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -868,8 +868,7 @@ static int fill_ctrlset(struct zd_mac *mac, unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; struct ieee80211_rate *txrate; - struct zd_ctrlset *cs = (struct zd_ctrlset *) - skb_push(skb, sizeof(struct zd_ctrlset)); + struct zd_ctrlset *cs = skb_push(skb, sizeof(struct zd_ctrlset)); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ZD_ASSERT(frag_len <= 0xffff); @@ -1103,7 +1102,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) } /* FIXME : could we avoid this big memcpy ? */ - memcpy(skb_put(skb, length), buffer, length); + skb_put_data(skb, buffer, length); memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); ieee80211_rx_irqsafe(hw, skb); |