diff options
Diffstat (limited to 'drivers/net/wireless/ath')
124 files changed, 7203 insertions, 6581 deletions
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 507d9a9ee69..f92050617ae 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1090,7 +1090,8 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ar5523_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ar5523 *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index b59cfbe0276..a889fd66fc6 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -56,6 +56,15 @@ enum ath_device_state { ATH_HW_INITIALIZED, }; +enum ath_op_flags { + ATH_OP_INVALID, + ATH_OP_BEACONS, + ATH_OP_ANI_RUN, + ATH_OP_PRIM_STA_VIF, + ATH_OP_HW_RESET, + ATH_OP_SCANNING, +}; + enum ath_bus_type { ATH_PCI, ATH_AHB, @@ -63,7 +72,7 @@ enum ath_bus_type { }; struct reg_dmn_pair_mapping { - u16 regDmnEnum; + u16 reg_domain; u16 reg_5ghz_ctl; u16 reg_2ghz_ctl; }; @@ -130,6 +139,7 @@ struct ath_common { struct ieee80211_hw *hw; int debug_mask; enum ath_device_state state; + unsigned long op_flags; struct ath_ani ani; @@ -161,6 +171,9 @@ struct ath_common { bool btcoex_enabled; bool disable_ani; bool bt_ant_diversity; + + int last_rssi; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index a1f09962885..17d221abd58 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -175,7 +175,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, return 0; } -int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) +int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result) { struct bmi_cmd cmd; union bmi_resp resp; @@ -184,7 +184,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) int ret; ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n", - address, *param); + address, param); if (ar->bmi.done_sent) { ath10k_warn("command disallowed\n"); @@ -193,7 +193,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) cmd.id = __cpu_to_le32(BMI_EXECUTE); cmd.execute.addr = __cpu_to_le32(address); - cmd.execute.param = __cpu_to_le32(*param); + cmd.execute.param = __cpu_to_le32(param); ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen); if (ret) { @@ -204,10 +204,13 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param) if (resplen < sizeof(resp.execute)) { ath10k_warn("invalid execute response length (%d)\n", resplen); - return ret; + return -EIO; } - *param = __le32_to_cpu(resp.execute.result); + *result = __le32_to_cpu(resp.execute.result); + + ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 8d81ce1cec2..111ab701465 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -201,7 +201,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address, \ addr = host_interest_item_address(HI_ITEM(item)); \ ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \ - *val = __le32_to_cpu(tmp); \ + if (!ret) \ + *val = __le32_to_cpu(tmp); \ ret; \ }) @@ -217,7 +218,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address, ret; \ }) -int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param); +int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result); int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address); int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length); int ath10k_bmi_fast_download(struct ath10k *ar, u32 address, diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index d44d618b05f..d185dc0cd12 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -266,12 +266,12 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, * ath10k_ce_sendlist_send. * The caller takes responsibility for any needed locking. */ -static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, - void *per_transfer_context, - u32 buffer, - unsigned int nbytes, - unsigned int transfer_id, - unsigned int flags) +int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, + void *per_transfer_context, + u32 buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags) { struct ath10k *ar = ce_state->ar; struct ath10k_ce_ring *src_ring = ce_state->src_ring; @@ -329,6 +329,33 @@ exit: return ret; } +void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) +{ + struct ath10k *ar = pipe->ar; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_ring *src_ring = pipe->src_ring; + u32 ctrl_addr = pipe->ctrl_addr; + + lockdep_assert_held(&ar_pci->ce_lock); + + /* + * This function must be called only if there is an incomplete + * scatter-gather transfer (before index register is updated) + * that needs to be cleaned up. + */ + if (WARN_ON_ONCE(src_ring->write_index == src_ring->sw_index)) + return; + + if (WARN_ON_ONCE(src_ring->write_index == + ath10k_ce_src_ring_write_index_get(ar, ctrl_addr))) + return; + + src_ring->write_index--; + src_ring->write_index &= src_ring->nentries_mask; + + src_ring->per_transfer_context[src_ring->write_index] = NULL; +} + int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, u32 buffer, @@ -840,35 +867,17 @@ void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state, static int ath10k_ce_init_src_ring(struct ath10k *ar, unsigned int ce_id, - struct ath10k_ce_pipe *ce_state, const struct ce_attr *attr) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_ring *src_ring; - unsigned int nentries = attr->src_nentries; - unsigned int ce_nbytes; - u32 ctrl_addr = ath10k_ce_base_address(ce_id); - dma_addr_t base_addr; - char *ptr; - - nentries = roundup_pow_of_two(nentries); - - if (ce_state->src_ring) { - WARN_ON(ce_state->src_ring->nentries != nentries); - return 0; - } - - ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *)); - ptr = kzalloc(ce_nbytes, GFP_KERNEL); - if (ptr == NULL) - return -ENOMEM; + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_ring *src_ring = ce_state->src_ring; + u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); - ce_state->src_ring = (struct ath10k_ce_ring *)ptr; - src_ring = ce_state->src_ring; + nentries = roundup_pow_of_two(attr->src_nentries); - ptr += sizeof(struct ath10k_ce_ring); - src_ring->nentries = nentries; - src_ring->nentries_mask = nentries - 1; + memset(src_ring->per_transfer_context, 0, + nentries * sizeof(*src_ring->per_transfer_context)); src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); src_ring->sw_index &= src_ring->nentries_mask; @@ -878,21 +887,87 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, ath10k_ce_src_ring_write_index_get(ar, ctrl_addr); src_ring->write_index &= src_ring->nentries_mask; - src_ring->per_transfer_context = (void **)ptr; + ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, + src_ring->base_addr_ce_space); + ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries); + ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max); + ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); + + ath10k_dbg(ATH10K_DBG_BOOT, + "boot init ce src ring id %d entries %d base_addr %p\n", + ce_id, nentries, src_ring->base_addr_owner_space); + + return 0; +} + +static int ath10k_ce_init_dest_ring(struct ath10k *ar, + unsigned int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; + u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); + + nentries = roundup_pow_of_two(attr->dest_nentries); + + memset(dest_ring->per_transfer_context, 0, + nentries * sizeof(*dest_ring->per_transfer_context)); + + dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); + dest_ring->sw_index &= dest_ring->nentries_mask; + dest_ring->write_index = + ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); + dest_ring->write_index &= dest_ring->nentries_mask; + + ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, + dest_ring->base_addr_ce_space); + ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries); + ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); + + ath10k_dbg(ATH10K_DBG_BOOT, + "boot ce dest ring id %d entries %d base_addr %p\n", + ce_id, nentries, dest_ring->base_addr_owner_space); + + return 0; +} + +static struct ath10k_ce_ring * +ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_ce_ring *src_ring; + u32 nentries = attr->src_nentries; + dma_addr_t base_addr; + + nentries = roundup_pow_of_two(nentries); + + src_ring = kzalloc(sizeof(*src_ring) + + (nentries * + sizeof(*src_ring->per_transfer_context)), + GFP_KERNEL); + if (src_ring == NULL) + return ERR_PTR(-ENOMEM); + + src_ring->nentries = nentries; + src_ring->nentries_mask = nentries - 1; /* * Legacy platforms that do not support cache * coherent DMA are unsupported */ src_ring->base_addr_owner_space_unaligned = - pci_alloc_consistent(ar_pci->pdev, - (nentries * sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - &base_addr); + dma_alloc_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + &base_addr, GFP_KERNEL); if (!src_ring->base_addr_owner_space_unaligned) { - kfree(ce_state->src_ring); - ce_state->src_ring = NULL; - return -ENOMEM; + kfree(src_ring); + return ERR_PTR(-ENOMEM); } src_ring->base_addr_ce_space_unaligned = base_addr; @@ -912,88 +987,54 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, kmalloc((nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN), GFP_KERNEL); if (!src_ring->shadow_base_unaligned) { - pci_free_consistent(ar_pci->pdev, - (nentries * sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - src_ring->base_addr_owner_space, - src_ring->base_addr_ce_space); - kfree(ce_state->src_ring); - ce_state->src_ring = NULL; - return -ENOMEM; + dma_free_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + src_ring->base_addr_owner_space, + src_ring->base_addr_ce_space); + kfree(src_ring); + return ERR_PTR(-ENOMEM); } src_ring->shadow_base = PTR_ALIGN( src_ring->shadow_base_unaligned, CE_DESC_RING_ALIGN); - ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, - src_ring->base_addr_ce_space); - ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries); - ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max); - ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0); - ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0); - ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries); - - ath10k_dbg(ATH10K_DBG_BOOT, - "boot ce src ring id %d entries %d base_addr %p\n", - ce_id, nentries, src_ring->base_addr_owner_space); - - return 0; + return src_ring; } -static int ath10k_ce_init_dest_ring(struct ath10k *ar, - unsigned int ce_id, - struct ath10k_ce_pipe *ce_state, - const struct ce_attr *attr) +static struct ath10k_ce_ring * +ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *dest_ring; - unsigned int nentries = attr->dest_nentries; - unsigned int ce_nbytes; - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 nentries; dma_addr_t base_addr; - char *ptr; - nentries = roundup_pow_of_two(nentries); + nentries = roundup_pow_of_two(attr->dest_nentries); - if (ce_state->dest_ring) { - WARN_ON(ce_state->dest_ring->nentries != nentries); - return 0; - } - - ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *)); - ptr = kzalloc(ce_nbytes, GFP_KERNEL); - if (ptr == NULL) - return -ENOMEM; + dest_ring = kzalloc(sizeof(*dest_ring) + + (nentries * + sizeof(*dest_ring->per_transfer_context)), + GFP_KERNEL); + if (dest_ring == NULL) + return ERR_PTR(-ENOMEM); - ce_state->dest_ring = (struct ath10k_ce_ring *)ptr; - dest_ring = ce_state->dest_ring; - - ptr += sizeof(struct ath10k_ce_ring); dest_ring->nentries = nentries; dest_ring->nentries_mask = nentries - 1; - dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); - dest_ring->sw_index &= dest_ring->nentries_mask; - dest_ring->write_index = - ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); - dest_ring->write_index &= dest_ring->nentries_mask; - - dest_ring->per_transfer_context = (void **)ptr; - /* * Legacy platforms that do not support cache * coherent DMA are unsupported */ dest_ring->base_addr_owner_space_unaligned = - pci_alloc_consistent(ar_pci->pdev, - (nentries * sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - &base_addr); + dma_alloc_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + &base_addr, GFP_KERNEL); if (!dest_ring->base_addr_owner_space_unaligned) { - kfree(ce_state->dest_ring); - ce_state->dest_ring = NULL; - return -ENOMEM; + kfree(dest_ring); + return ERR_PTR(-ENOMEM); } dest_ring->base_addr_ce_space_unaligned = base_addr; @@ -1012,39 +1053,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, dest_ring->base_addr_ce_space_unaligned, CE_DESC_RING_ALIGN); - ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, - dest_ring->base_addr_ce_space); - ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries); - ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0); - ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0); - ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries); - - ath10k_dbg(ATH10K_DBG_BOOT, - "boot ce dest ring id %d entries %d base_addr %p\n", - ce_id, nentries, dest_ring->base_addr_owner_space); - - return 0; -} - -static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar, - unsigned int ce_id, - const struct ce_attr *attr) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; - u32 ctrl_addr = ath10k_ce_base_address(ce_id); - - spin_lock_bh(&ar_pci->ce_lock); - - ce_state->ar = ar; - ce_state->id = ce_id; - ce_state->ctrl_addr = ctrl_addr; - ce_state->attr_flags = attr->flags; - ce_state->src_sz_max = attr->src_sz_max; - - spin_unlock_bh(&ar_pci->ce_lock); - - return ce_state; + return dest_ring; } /* @@ -1054,11 +1063,11 @@ static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar, * initialization. It may be that only one side or the other is * initialized by software/firmware. */ -struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, - unsigned int ce_id, - const struct ce_attr *attr) +int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) { - struct ath10k_ce_pipe *ce_state; + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; int ret; /* @@ -1067,71 +1076,135 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, * * For the lack of a better place do the check here. */ - BUILD_BUG_ON(TARGET_NUM_MSDU_DESC > + BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - BUILD_BUG_ON(TARGET_10X_NUM_MSDU_DESC > + BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); ret = ath10k_pci_wake(ar); if (ret) - return NULL; + return ret; - ce_state = ath10k_ce_init_state(ar, ce_id, attr); - if (!ce_state) { - ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id); - goto out; - } + spin_lock_bh(&ar_pci->ce_lock); + ce_state->ar = ar; + ce_state->id = ce_id; + ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); + ce_state->attr_flags = attr->flags; + ce_state->src_sz_max = attr->src_sz_max; + spin_unlock_bh(&ar_pci->ce_lock); if (attr->src_nentries) { - ret = ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr); + ret = ath10k_ce_init_src_ring(ar, ce_id, attr); if (ret) { ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", ce_id, ret); - ath10k_ce_deinit(ce_state); - ce_state = NULL; goto out; } } if (attr->dest_nentries) { - ret = ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr); + ret = ath10k_ce_init_dest_ring(ar, ce_id, attr); if (ret) { ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", ce_id, ret); - ath10k_ce_deinit(ce_state); - ce_state = NULL; goto out; } } out: ath10k_pci_sleep(ar); - return ce_state; + return ret; } -void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state) +static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) +{ + u32 ctrl_addr = ath10k_ce_base_address(ce_id); + + ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, 0); +} + +static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id) +{ + u32 ctrl_addr = ath10k_ce_base_address(ce_id); + + ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, 0); +} + +void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) +{ + int ret; + + ret = ath10k_pci_wake(ar); + if (ret) + return; + + ath10k_ce_deinit_src_ring(ar, ce_id); + ath10k_ce_deinit_dest_ring(ar, ce_id); + + ath10k_pci_sleep(ar); +} + +int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + int ret; + + if (attr->src_nentries) { + ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); + if (IS_ERR(ce_state->src_ring)) { + ret = PTR_ERR(ce_state->src_ring); + ath10k_err("failed to allocate copy engine source ring %d: %d\n", + ce_id, ret); + ce_state->src_ring = NULL; + return ret; + } + } + + if (attr->dest_nentries) { + ce_state->dest_ring = ath10k_ce_alloc_dest_ring(ar, ce_id, + attr); + if (IS_ERR(ce_state->dest_ring)) { + ret = PTR_ERR(ce_state->dest_ring); + ath10k_err("failed to allocate copy engine destination ring %d: %d\n", + ce_id, ret); + ce_state->dest_ring = NULL; + return ret; + } + } + + return 0; +} + +void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { - struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; if (ce_state->src_ring) { kfree(ce_state->src_ring->shadow_base_unaligned); - pci_free_consistent(ar_pci->pdev, - (ce_state->src_ring->nentries * - sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - ce_state->src_ring->base_addr_owner_space, - ce_state->src_ring->base_addr_ce_space); + dma_free_coherent(ar->dev, + (ce_state->src_ring->nentries * + sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + ce_state->src_ring->base_addr_owner_space, + ce_state->src_ring->base_addr_ce_space); kfree(ce_state->src_ring); } if (ce_state->dest_ring) { - pci_free_consistent(ar_pci->pdev, - (ce_state->dest_ring->nentries * - sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - ce_state->dest_ring->base_addr_owner_space, - ce_state->dest_ring->base_addr_ce_space); + dma_free_coherent(ar->dev, + (ce_state->dest_ring->nentries * + sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + ce_state->dest_ring->base_addr_owner_space, + ce_state->dest_ring->base_addr_ce_space); kfree(ce_state->dest_ring); } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 67dbde6a5c7..7a5a36fc59c 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -23,7 +23,7 @@ /* Maximum number of Copy Engine's supported */ #define CE_COUNT_MAX 8 -#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048 +#define CE_HTT_H2T_MSG_SRC_NENTRIES 4096 /* Descriptor rings must be aligned to this boundary */ #define CE_DESC_RING_ALIGN 8 @@ -104,7 +104,8 @@ struct ath10k_ce_ring { void *shadow_base_unaligned; struct ce_desc *shadow_base; - void **per_transfer_context; + /* keep last */ + void *per_transfer_context[0]; }; struct ath10k_ce_pipe { @@ -152,6 +153,15 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, unsigned int transfer_id, unsigned int flags); +int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, + void *per_transfer_context, + u32 buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags); + +void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe); + void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, void (*send_cb)(struct ath10k_ce_pipe *), int disable_interrupts); @@ -203,10 +213,12 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, /*==================CE Engine Initialization=======================*/ -/* Initialize an instance of a CE */ -struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, - unsigned int ce_id, - const struct ce_attr *attr); +int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr); +void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); +int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, + const struct ce_attr *attr); +void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id); /*==================CE Engine Shutdown=======================*/ /* @@ -229,8 +241,6 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, unsigned int *nbytesp, unsigned int *transfer_idp); -void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state); - /*==================CE Interrupt Handlers====================*/ void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3b59af3bddf..e6c56c5bb0f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -55,38 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) { ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); - ar->is_target_paused = true; - wake_up(&ar->event_queue); -} - -static int ath10k_init_connect_htc(struct ath10k *ar) -{ - int status; - - status = ath10k_wmi_connect_htc_service(ar); - if (status) - goto conn_fail; - - /* Start HTC */ - status = ath10k_htc_start(&ar->htc); - if (status) - goto conn_fail; - - /* Wait for WMI event to be ready */ - status = ath10k_wmi_wait_for_service_ready(ar); - if (status <= 0) { - ath10k_warn("wmi service ready event not received"); - status = -ETIMEDOUT; - goto timeout; - } - - ath10k_dbg(ATH10K_DBG_BOOT, "boot wmi ready\n"); - return 0; - -timeout: - ath10k_htc_stop(&ar->htc); -conn_fail: - return status; + complete(&ar->target_suspend); } static int ath10k_init_configure_target(struct ath10k *ar) @@ -250,30 +219,40 @@ exit: static int ath10k_download_and_run_otp(struct ath10k *ar) { - u32 address = ar->hw_params.patch_load_addr; - u32 exec_param; + u32 result, address = ar->hw_params.patch_load_addr; int ret; /* OTP is optional */ - if (!ar->otp_data || !ar->otp_len) + if (!ar->otp_data || !ar->otp_len) { + ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", + ar->otp_data, ar->otp_len); return 0; + } + + ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", + address, ar->otp_len); ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); if (ret) { ath10k_err("could not write otp (%d)\n", ret); - goto exit; + return ret; } - exec_param = 0; - ret = ath10k_bmi_execute(ar, address, &exec_param); + ret = ath10k_bmi_execute(ar, address, 0, &result); if (ret) { ath10k_err("could not execute otp (%d)\n", ret); - goto exit; + return ret; } -exit: - return ret; + ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + + if (result != 0) { + ath10k_err("otp calibration failed: %d", result); + return -EINVAL; + } + + return 0; } static int ath10k_download_fw(struct ath10k *ar) @@ -390,8 +369,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) /* first fetch the firmware file (firmware-*.bin) */ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); if (IS_ERR(ar->firmware)) { - ath10k_err("Could not fetch firmware file '%s': %ld\n", - name, PTR_ERR(ar->firmware)); + ath10k_err("could not fetch firmware file '%s/%s': %ld\n", + ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware)); return PTR_ERR(ar->firmware); } @@ -402,14 +381,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; if (len < magic_len) { - ath10k_err("firmware image too small to contain magic: %zu\n", - len); + ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n", + ar->hw_params.fw.dir, name, len); ret = -EINVAL; goto err; } if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { - ath10k_err("Invalid firmware magic\n"); + ath10k_err("invalid firmware magic\n"); ret = -EINVAL; goto err; } @@ -431,7 +410,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) data += sizeof(*hdr); if (len < ie_len) { - ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n", + ath10k_err("invalid length for FW IE %d (%zu < %zu)\n", ie_id, len, ie_len); ret = -EINVAL; goto err; @@ -470,8 +449,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) if (index == ie_len) break; - if (data[index] & (1 << bit)) + if (data[index] & (1 << bit)) { + ath10k_dbg(ATH10K_DBG_BOOT, + "Enabling feature bit: %i\n", + i); __set_bit(i, ar->fw_features); + } } ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", @@ -510,8 +493,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) } if (!ar->firmware_data || !ar->firmware_len) { - ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n", - name); + ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", + ar->hw_params.fw.dir, name); ret = -ENOMEDIUM; goto err; } @@ -528,7 +511,9 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ar->hw_params.fw.board); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); - ath10k_err("could not fetch board data (%d)\n", ret); + ath10k_err("could not fetch board data '%s/%s' (%d)\n", + ar->hw_params.fw.dir, ar->hw_params.fw.board, + ret); goto err; } @@ -546,19 +531,21 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret; + ar->fw_api = 2; + ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); - if (ret == 0) { - ar->fw_api = 2; - goto out; - } + if (ret == 0) + goto success; + + ar->fw_api = 1; + ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_1(ar); if (ret) return ret; - ar->fw_api = 1; - -out: +success: ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; @@ -569,16 +556,22 @@ static int ath10k_init_download_firmware(struct ath10k *ar) int ret; ret = ath10k_download_board_data(ar); - if (ret) + if (ret) { + ath10k_err("failed to download board data: %d\n", ret); return ret; + } ret = ath10k_download_and_run_otp(ar); - if (ret) + if (ret) { + ath10k_err("failed to run otp: %d\n", ret); return ret; + } ret = ath10k_download_fw(ar); - if (ret) + if (ret) { + ath10k_err("failed to download firmware: %d\n", ret); return ret; + } return ret; } @@ -657,8 +650,9 @@ static void ath10k_core_restart(struct work_struct *work) switch (ar->state) { case ATH10K_STATE_ON: - ath10k_halt(ar); ar->state = ATH10K_STATE_RESTARTING; + del_timer_sync(&ar->scan.timeout); + ath10k_reset_scan((unsigned long)ar); ieee80211_restart_hw(ar->hw); break; case ATH10K_STATE_OFF: @@ -667,6 +661,8 @@ static void ath10k_core_restart(struct work_struct *work) ath10k_warn("cannot restart a device that hasn't been started\n"); break; case ATH10K_STATE_RESTARTING: + /* hw restart might be requested from multiple places */ + break; case ATH10K_STATE_RESTARTED: ar->state = ATH10K_STATE_WEDGED; /* fall through */ @@ -678,71 +674,6 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); } -struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, - const struct ath10k_hif_ops *hif_ops) -{ - struct ath10k *ar; - - ar = ath10k_mac_create(); - if (!ar) - return NULL; - - ar->ath_common.priv = ar; - ar->ath_common.hw = ar->hw; - - ar->p2p = !!ath10k_p2p; - ar->dev = dev; - - ar->hif.priv = hif_priv; - ar->hif.ops = hif_ops; - - init_completion(&ar->scan.started); - init_completion(&ar->scan.completed); - init_completion(&ar->scan.on_channel); - - init_completion(&ar->install_key_done); - init_completion(&ar->vdev_setup_done); - - setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar); - - ar->workqueue = create_singlethread_workqueue("ath10k_wq"); - if (!ar->workqueue) - goto err_wq; - - mutex_init(&ar->conf_mutex); - spin_lock_init(&ar->data_lock); - - INIT_LIST_HEAD(&ar->peers); - init_waitqueue_head(&ar->peer_mapping_wq); - - init_completion(&ar->offchan_tx_completed); - INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); - skb_queue_head_init(&ar->offchan_tx_queue); - - INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); - skb_queue_head_init(&ar->wmi_mgmt_tx_queue); - - init_waitqueue_head(&ar->event_queue); - - INIT_WORK(&ar->restart_work, ath10k_core_restart); - - return ar; - -err_wq: - ath10k_mac_destroy(ar); - return NULL; -} -EXPORT_SYMBOL(ath10k_core_create); - -void ath10k_core_destroy(struct ath10k *ar) -{ - flush_workqueue(ar->workqueue); - destroy_workqueue(ar->workqueue); - - ath10k_mac_destroy(ar); -} -EXPORT_SYMBOL(ath10k_core_destroy); - int ath10k_core_start(struct ath10k *ar) { int status; @@ -783,10 +714,28 @@ int ath10k_core_start(struct ath10k *ar) goto err; } + status = ath10k_htt_init(ar); + if (status) { + ath10k_err("failed to init htt: %d\n", status); + goto err_wmi_detach; + } + + status = ath10k_htt_tx_alloc(&ar->htt); + if (status) { + ath10k_err("failed to alloc htt tx: %d\n", status); + goto err_wmi_detach; + } + + status = ath10k_htt_rx_alloc(&ar->htt); + if (status) { + ath10k_err("failed to alloc htt rx: %d\n", status); + goto err_htt_tx_detach; + } + status = ath10k_hif_start(ar); if (status) { ath10k_err("could not start HIF: %d\n", status); - goto err_wmi_detach; + goto err_htt_rx_detach; } status = ath10k_htc_wait_target(&ar->htc); @@ -795,15 +744,30 @@ int ath10k_core_start(struct ath10k *ar) goto err_hif_stop; } - status = ath10k_htt_attach(ar); + status = ath10k_htt_connect(&ar->htt); if (status) { - ath10k_err("could not attach htt (%d)\n", status); + ath10k_err("failed to connect htt (%d)\n", status); goto err_hif_stop; } - status = ath10k_init_connect_htc(ar); - if (status) - goto err_htt_detach; + status = ath10k_wmi_connect(ar); + if (status) { + ath10k_err("could not connect wmi: %d\n", status); + goto err_hif_stop; + } + + status = ath10k_htc_start(&ar->htc); + if (status) { + ath10k_err("failed to start htc: %d\n", status); + goto err_hif_stop; + } + + status = ath10k_wmi_wait_for_service_ready(ar); + if (status <= 0) { + ath10k_warn("wmi service ready event not received"); + status = -ETIMEDOUT; + goto err_htc_stop; + } ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n", ar->hw->wiphy->fw_version); @@ -811,31 +775,40 @@ int ath10k_core_start(struct ath10k *ar) status = ath10k_wmi_cmd_init(ar); if (status) { ath10k_err("could not send WMI init command (%d)\n", status); - goto err_disconnect_htc; + goto err_htc_stop; } status = ath10k_wmi_wait_for_unified_ready(ar); if (status <= 0) { ath10k_err("wmi unified ready event not received\n"); status = -ETIMEDOUT; - goto err_disconnect_htc; + goto err_htc_stop; } - status = ath10k_htt_attach_target(&ar->htt); - if (status) - goto err_disconnect_htc; + status = ath10k_htt_setup(&ar->htt); + if (status) { + ath10k_err("failed to setup htt: %d\n", status); + goto err_htc_stop; + } status = ath10k_debug_start(ar); if (status) - goto err_disconnect_htc; + goto err_htc_stop; + + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) + ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1; + else + ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; - ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; INIT_LIST_HEAD(&ar->arvifs); if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) - ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n", - ar->hw_params.name, ar->target_version, - ar->hw->wiphy->fw_version, ar->fw_api, + ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", + ar->hw_params.name, + ar->target_version, + ar->chip_id, + ar->hw->wiphy->fw_version, + ar->fw_api, ar->htt.target_version_major, ar->htt.target_version_minor); @@ -843,12 +816,14 @@ int ath10k_core_start(struct ath10k *ar) return 0; -err_disconnect_htc: +err_htc_stop: ath10k_htc_stop(&ar->htc); -err_htt_detach: - ath10k_htt_detach(&ar->htt); err_hif_stop: ath10k_hif_stop(ar); +err_htt_rx_detach: + ath10k_htt_rx_free(&ar->htt); +err_htt_tx_detach: + ath10k_htt_tx_free(&ar->htt); err_wmi_detach: ath10k_wmi_detach(ar); err: @@ -856,13 +831,41 @@ err: } EXPORT_SYMBOL(ath10k_core_start); +int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt) +{ + int ret; + + reinit_completion(&ar->target_suspend); + + ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt); + if (ret) { + ath10k_warn("could not suspend target (%d)\n", ret); + return ret; + } + + ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); + + if (ret == 0) { + ath10k_warn("suspend timed out - target pause event never came\n"); + return -ETIMEDOUT; + } + + return 0; +} + void ath10k_core_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); + /* try to suspend target */ + if (ar->state != ATH10K_STATE_RESTARTING) + ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); + ath10k_debug_stop(ar); ath10k_htc_stop(&ar->htc); - ath10k_htt_detach(&ar->htt); + ath10k_hif_stop(ar); + ath10k_htt_tx_free(&ar->htt); + ath10k_htt_rx_free(&ar->htt); ath10k_wmi_detach(ar); } EXPORT_SYMBOL(ath10k_core_stop); @@ -954,22 +957,15 @@ static int ath10k_core_check_chip_id(struct ath10k *ar) return 0; } -int ath10k_core_register(struct ath10k *ar, u32 chip_id) +static void ath10k_core_register_work(struct work_struct *work) { + struct ath10k *ar = container_of(work, struct ath10k, register_work); int status; - ar->chip_id = chip_id; - - status = ath10k_core_check_chip_id(ar); - if (status) { - ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id); - return status; - } - status = ath10k_core_probe_fw(ar); if (status) { ath10k_err("could not probe fw (%d)\n", status); - return status; + goto err; } status = ath10k_mac_register(ar); @@ -984,18 +980,43 @@ int ath10k_core_register(struct ath10k *ar, u32 chip_id) goto err_unregister_mac; } - return 0; + set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); + return; err_unregister_mac: ath10k_mac_unregister(ar); err_release_fw: ath10k_core_free_firmware_files(ar); - return status; +err: + device_release_driver(ar->dev); + return; +} + +int ath10k_core_register(struct ath10k *ar, u32 chip_id) +{ + int status; + + ar->chip_id = chip_id; + + status = ath10k_core_check_chip_id(ar); + if (status) { + ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id); + return status; + } + + queue_work(ar->workqueue, &ar->register_work); + + return 0; } EXPORT_SYMBOL(ath10k_core_register); void ath10k_core_unregister(struct ath10k *ar) { + cancel_work_sync(&ar->register_work); + + if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) + return; + /* We must unregister from mac80211 before we stop HTC and HIF. * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ @@ -1007,6 +1028,71 @@ void ath10k_core_unregister(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_unregister); +struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, + const struct ath10k_hif_ops *hif_ops) +{ + struct ath10k *ar; + + ar = ath10k_mac_create(); + if (!ar) + return NULL; + + ar->ath_common.priv = ar; + ar->ath_common.hw = ar->hw; + + ar->p2p = !!ath10k_p2p; + ar->dev = dev; + + ar->hif.priv = hif_priv; + ar->hif.ops = hif_ops; + + init_completion(&ar->scan.started); + init_completion(&ar->scan.completed); + init_completion(&ar->scan.on_channel); + init_completion(&ar->target_suspend); + + init_completion(&ar->install_key_done); + init_completion(&ar->vdev_setup_done); + + setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar); + + ar->workqueue = create_singlethread_workqueue("ath10k_wq"); + if (!ar->workqueue) + goto err_wq; + + mutex_init(&ar->conf_mutex); + spin_lock_init(&ar->data_lock); + + INIT_LIST_HEAD(&ar->peers); + init_waitqueue_head(&ar->peer_mapping_wq); + + init_completion(&ar->offchan_tx_completed); + INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); + skb_queue_head_init(&ar->offchan_tx_queue); + + INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + + INIT_WORK(&ar->register_work, ath10k_core_register_work); + INIT_WORK(&ar->restart_work, ath10k_core_restart); + + return ar; + +err_wq: + ath10k_mac_destroy(ar); + return NULL; +} +EXPORT_SYMBOL(ath10k_core_create); + +void ath10k_core_destroy(struct ath10k *ar) +{ + flush_workqueue(ar->workqueue); + destroy_workqueue(ar->workqueue); + + ath10k_mac_destroy(ar); +} +EXPORT_SYMBOL(ath10k_core_destroy); + MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ade1781c718..68ceef61933 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -46,21 +46,35 @@ #define ATH10K_MAX_NUM_MGMT_PENDING 128 +/* number of failed packets */ +#define ATH10K_KICKOUT_THRESHOLD 50 + +/* + * Use insanely high numbers to make sure that the firmware implementation + * won't start, we have the same functionality already in hostapd. Unit + * is seconds. + */ +#define ATH10K_KEEPALIVE_MIN_IDLE 3747 +#define ATH10K_KEEPALIVE_MAX_IDLE 3895 +#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900 + struct ath10k; struct ath10k_skb_cb { dma_addr_t paddr; - bool is_mapped; - bool is_aborted; u8 vdev_id; struct { u8 tid; bool is_offchan; - - u8 frag_len; - u8 pad_len; + struct ath10k_htt_txbuf *txbuf; + u32 txbuf_paddr; } __packed htt; + + struct { + bool dtim_zero; + bool deliver_cab; + } bcn; } __packed; static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) @@ -70,32 +84,6 @@ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data; } -static inline int ath10k_skb_map(struct device *dev, struct sk_buff *skb) -{ - if (ATH10K_SKB_CB(skb)->is_mapped) - return -EINVAL; - - ATH10K_SKB_CB(skb)->paddr = dma_map_single(dev, skb->data, skb->len, - DMA_TO_DEVICE); - - if (unlikely(dma_mapping_error(dev, ATH10K_SKB_CB(skb)->paddr))) - return -EIO; - - ATH10K_SKB_CB(skb)->is_mapped = true; - return 0; -} - -static inline int ath10k_skb_unmap(struct device *dev, struct sk_buff *skb) -{ - if (!ATH10K_SKB_CB(skb)->is_mapped) - return -EINVAL; - - dma_unmap_single(dev, ATH10K_SKB_CB(skb)->paddr, skb->len, - DMA_TO_DEVICE); - ATH10K_SKB_CB(skb)->is_mapped = false; - return 0; -} - static inline u32 host_interest_item_address(u32 item_offset) { return QCA988X_HOST_INTEREST_ADDRESS + item_offset; @@ -131,6 +119,7 @@ struct ath10k_peer_stat { u8 peer_macaddr[ETH_ALEN]; u32 peer_rssi; u32 peer_tx_rate; + u32 peer_rx_rate; /* 10x only */ }; struct ath10k_target_stats { @@ -142,6 +131,12 @@ struct ath10k_target_stats { u32 cycle_count; u32 phy_err_count; u32 chan_tx_power; + u32 ack_rx_bad; + u32 rts_bad; + u32 rts_good; + u32 fcs_bad; + u32 no_beacons; + u32 mib_int_count; /* PDEV TX stats */ s32 comp_queued; @@ -211,6 +206,18 @@ struct ath10k_peer { struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; }; +struct ath10k_sta { + struct ath10k_vif *arvif; + + /* the following are protected by ar->data_lock */ + u32 changed; /* IEEE80211_RC_* */ + u32 bw; + u32 nss; + u32 smps; + + struct work_struct update_wk; +}; + #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) struct ath10k_vif { @@ -222,10 +229,17 @@ struct ath10k_vif { u32 beacon_interval; u32 dtim_period; struct sk_buff *beacon; + /* protected by data_lock */ + bool beacon_sent; struct ath10k *ar; struct ieee80211_vif *vif; + bool is_started; + bool is_up; + u32 aid; + u8 bssid[ETH_ALEN]; + struct work_struct wep_key_work; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; u8 def_wep_key_idx; @@ -235,7 +249,6 @@ struct ath10k_vif { union { struct { - u8 bssid[ETH_ALEN]; u32 uapsd; } sta; struct { @@ -249,13 +262,13 @@ struct ath10k_vif { u32 noa_len; u8 *noa_data; } ap; - struct { - u8 bssid[ETH_ALEN]; - } ibss; } u; u8 fixed_rate; u8 fixed_nss; + u8 force_sgi; + bool use_cts_prot; + int num_legacy_stations; }; struct ath10k_vif_iter { @@ -322,6 +335,7 @@ enum ath10k_dev_flags { /* Indicates that ath10k device is during CAC phase of DFS */ ATH10K_CAC_RUNNING, ATH10K_FLAG_FIRST_BOOT_DONE, + ATH10K_FLAG_CORE_REGISTERED, }; struct ath10k { @@ -355,8 +369,7 @@ struct ath10k { const struct ath10k_hif_ops *ops; } hif; - wait_queue_head_t event_queue; - bool is_target_paused; + struct completion target_suspend; struct ath10k_bmi bmi; struct ath10k_wmi wmi; @@ -412,14 +425,28 @@ struct ath10k { /* valid during scan; needed for mgmt rx during scan */ struct ieee80211_channel *scan_channel; + /* current operating channel definition */ + struct cfg80211_chan_def chandef; + int free_vdev_map; + bool promisc; + bool monitor; int monitor_vdev_id; - bool monitor_enabled; - bool monitor_present; + bool monitor_started; unsigned int filter_flags; unsigned long dev_flags; u32 dfs_block_radar_events; + /* protected by conf_mutex */ + bool radar_enabled; + int num_started_vdevs; + + /* Protected by conf-mutex */ + u8 supp_tx_chainmask; + u8 supp_rx_chainmask; + u8 cfg_tx_chainmask; + u8 cfg_rx_chainmask; + struct wmi_pdev_set_wmm_params_arg wmm_params; struct completion install_key_done; @@ -450,6 +477,7 @@ struct ath10k { enum ath10k_state state; + struct work_struct register_work; struct work_struct restart_work; /* cycle count is reported twice for each visited channel during scan. @@ -470,6 +498,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, void ath10k_core_destroy(struct ath10k *ar); int ath10k_core_start(struct ath10k *ar); +int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar, u32 chip_id); void ath10k_core_unregister(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 6debd281350..1b7ff4ba122 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, u8 *tmp = ev->data; struct ath10k_target_stats *stats; int num_pdev_stats, num_vdev_stats, num_peer_stats; - struct wmi_pdev_stats *ps; + struct wmi_pdev_stats_10x *ps; int i; spin_lock_bh(&ar->data_lock); @@ -173,7 +173,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */ if (num_pdev_stats) { - ps = (struct wmi_pdev_stats *)tmp; + ps = (struct wmi_pdev_stats_10x *)tmp; stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf); stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count); @@ -228,7 +228,18 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop); stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs); - tmp += sizeof(struct wmi_pdev_stats); + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, + ar->fw_features)) { + stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad); + stats->rts_bad = __le32_to_cpu(ps->rts_bad); + stats->rts_good = __le32_to_cpu(ps->rts_good); + stats->fcs_bad = __le32_to_cpu(ps->fcs_bad); + stats->no_beacons = __le32_to_cpu(ps->no_beacons); + stats->mib_int_count = __le32_to_cpu(ps->mib_int_count); + tmp += sizeof(struct wmi_pdev_stats_10x); + } else { + tmp += sizeof(struct wmi_pdev_stats_old); + } } /* 0 or max vdevs */ @@ -243,22 +254,29 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, } if (num_peer_stats) { - struct wmi_peer_stats *peer_stats; + struct wmi_peer_stats_10x *peer_stats; struct ath10k_peer_stat *s; stats->peers = num_peer_stats; for (i = 0; i < num_peer_stats; i++) { - peer_stats = (struct wmi_peer_stats *)tmp; + peer_stats = (struct wmi_peer_stats_10x *)tmp; s = &stats->peer_stat[i]; - WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, - s->peer_macaddr); + memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr, + ETH_ALEN); s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi); s->peer_tx_rate = __le32_to_cpu(peer_stats->peer_tx_rate); - - tmp += sizeof(struct wmi_peer_stats); + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, + ar->fw_features)) { + s->peer_rx_rate = + __le32_to_cpu(peer_stats->peer_rx_rate); + tmp += sizeof(struct wmi_peer_stats_10x); + + } else { + tmp += sizeof(struct wmi_peer_stats_old); + } } } @@ -272,7 +290,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, struct ath10k *ar = file->private_data; struct ath10k_target_stats *fw_stats; char *buf = NULL; - unsigned int len = 0, buf_len = 2500; + unsigned int len = 0, buf_len = 8000; ssize_t ret_cnt = 0; long left; int i; @@ -320,6 +338,16 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, "Cycle count", fw_stats->cycle_count); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", "PHY error count", fw_stats->phy_err_count); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "RTS bad count", fw_stats->rts_bad); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "RTS good count", fw_stats->rts_good); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "FCS bad count", fw_stats->fcs_bad); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "No beacon count", fw_stats->no_beacons); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "MIB int count", fw_stats->mib_int_count); len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s\n", @@ -411,8 +439,8 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs); len += scnprintf(buf + len, buf_len - len, "\n"); - len += scnprintf(buf + len, buf_len - len, "%30s\n", - "ath10k PEER stats"); + len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n", + "ath10k PEER stats", fw_stats->peers); len += scnprintf(buf + len, buf_len - len, "%30s\n\n", "================="); @@ -425,6 +453,9 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, len += scnprintf(buf + len, buf_len - len, "%30s %u\n", "Peer TX rate", fw_stats->peer_stat[i].peer_tx_rate); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "Peer RX rate", + fw_stats->peer_stat[i].peer_rx_rate); len += scnprintf(buf + len, buf_len - len, "\n"); } spin_unlock_bh(&ar->data_lock); @@ -451,27 +482,37 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - const char buf[] = "To simulate firmware crash write the keyword" - " `crash` to this file.\nThis will force firmware" - " to report a crash to the host system.\n"; + const char buf[] = "To simulate firmware crash write one of the" + " keywords to this file:\n `soft` - this will send" + " WMI_FORCE_FW_HANG_ASSERT to firmware if FW" + " supports that command.\n `hard` - this will send" + " to firmware command with illegal parameters" + " causing firmware crash.\n"; + return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); } +/* Simulate firmware crash: + * 'soft': Call wmi command causing firmware hang. This firmware hang is + * recoverable by warm firmware reset. + * 'hard': Force firmware crash by setting any vdev parameter for not allowed + * vdev id. This is hard firmware crash because it is recoverable only by cold + * firmware reset. + */ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - char buf[32] = {}; + char buf[32]; int ret; mutex_lock(&ar->conf_mutex); simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); - if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) { - ret = -EINVAL; - goto exit; - } + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = 0; if (ar->state != ATH10K_STATE_ON && ar->state != ATH10K_STATE_RESTARTED) { @@ -479,14 +520,30 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, goto exit; } - ath10k_info("simulating firmware crash\n"); + /* drop the possible '\n' from the end */ + if (buf[count - 1] == '\n') { + buf[count - 1] = 0; + count--; + } - ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); - if (ret) - ath10k_warn("failed to force fw hang (%d)\n", ret); + if (!strcmp(buf, "soft")) { + ath10k_info("simulating soft firmware crash\n"); + ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); + } else if (!strcmp(buf, "hard")) { + ath10k_info("simulating hard firmware crash\n"); + ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1, + ar->wmi.vdev_param->rts_threshold, 0); + } else { + ret = -EINVAL; + goto exit; + } + + if (ret) { + ath10k_warn("failed to simulate firmware crash: %d\n", ret); + goto exit; + } - if (ret == 0) - ret = count; + ret = count; exit: mutex_unlock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 1773c36c71a..a5824990bd2 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, #ifdef CONFIG_ATH10K_DEBUG __printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask, - const char *fmt, ...); + const char *fmt, ...); void ath10k_dbg_dump(enum ath10k_debug_mask mask, const char *msg, const char *prefix, const void *buf, size_t len); diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index dcdea68bcc0..2ac7beacddc 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -21,6 +21,14 @@ #include <linux/kernel.h> #include "core.h" +struct ath10k_hif_sg_item { + u16 transfer_id; + void *transfer_context; /* NULL = tx completion callback not called */ + void *vaddr; /* for debugging mostly */ + u32 paddr; + u16 len; +}; + struct ath10k_hif_cb { int (*tx_completion)(struct ath10k *ar, struct sk_buff *wbuf, @@ -31,11 +39,9 @@ struct ath10k_hif_cb { }; struct ath10k_hif_ops { - /* Send the head of a buffer to HIF for transmission to the target. */ - int (*send_head)(struct ath10k *ar, u8 pipe_id, - unsigned int transfer_id, - unsigned int nbytes, - struct sk_buff *buf); + /* send a scatter-gather list to the target */ + int (*tx_sg)(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items); /* * API to handle HIF-specific BMI message exchanges, this API is @@ -86,12 +92,11 @@ struct ath10k_hif_ops { }; -static inline int ath10k_hif_send_head(struct ath10k *ar, u8 pipe_id, - unsigned int transfer_id, - unsigned int nbytes, - struct sk_buff *buf) +static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, + int n_items) { - return ar->hif.ops->send_head(ar, pipe_id, transfer_id, nbytes, buf); + return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items); } static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index edc57ab505c..e493db4b4a4 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -63,7 +63,9 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar) static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc, struct sk_buff *skb) { - ath10k_skb_unmap(htc->ar->dev, skb); + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); + + dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); skb_pull(skb, sizeof(struct ath10k_htc_hdr)); } @@ -122,6 +124,9 @@ int ath10k_htc_send(struct ath10k_htc *htc, struct sk_buff *skb) { struct ath10k_htc_ep *ep = &htc->endpoint[eid]; + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); + struct ath10k_hif_sg_item sg_item; + struct device *dev = htc->ar->dev; int credits = 0; int ret; @@ -152,28 +157,40 @@ int ath10k_htc_send(struct ath10k_htc *htc, goto err_pull; } ep->tx_credits -= credits; + ath10k_dbg(ATH10K_DBG_HTC, + "htc ep %d consumed %d credits (total %d)\n", + eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); } ath10k_htc_prepare_tx_skb(ep, skb); - ret = ath10k_skb_map(htc->ar->dev, skb); + skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); + ret = dma_mapping_error(dev, skb_cb->paddr); if (ret) goto err_credits; - ret = ath10k_hif_send_head(htc->ar, ep->ul_pipe_id, ep->eid, - skb->len, skb); + sg_item.transfer_id = ep->eid; + sg_item.transfer_context = skb; + sg_item.vaddr = skb->data; + sg_item.paddr = skb_cb->paddr; + sg_item.len = skb->len; + + ret = ath10k_hif_tx_sg(htc->ar, ep->ul_pipe_id, &sg_item, 1); if (ret) goto err_unmap; return 0; err_unmap: - ath10k_skb_unmap(htc->ar->dev, skb); + dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); err_credits: if (ep->tx_credit_flow_enabled) { spin_lock_bh(&htc->tx_lock); ep->tx_credits += credits; + ath10k_dbg(ATH10K_DBG_HTC, + "htc ep %d reverted %d credits back (total %d)\n", + eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); if (ep->ep_ops.ep_tx_credits) @@ -191,10 +208,8 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_ep *ep = &htc->endpoint[eid]; - if (!skb) { - ath10k_warn("invalid sk_buff completion - NULL pointer. firmware crashed?\n"); + if (WARN_ON_ONCE(!skb)) return 0; - } ath10k_htc_notify_tx_completion(ep, skb); /* the skb now belongs to the completion handler */ @@ -225,12 +240,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc, if (report->eid >= ATH10K_HTC_EP_COUNT) break; - ath10k_dbg(ATH10K_DBG_HTC, "ep %d got %d credits\n", - report->eid, report->credits); - ep = &htc->endpoint[report->eid]; ep->tx_credits += report->credits; + ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", + report->eid, report->credits, ep->tx_credits); + if (ep->ep_ops.ep_tx_credits) { spin_unlock_bh(&htc->tx_lock); ep->ep_ops.ep_tx_credits(htc->ar); @@ -815,17 +830,11 @@ int ath10k_htc_start(struct ath10k_htc *htc) return 0; } -/* - * stop HTC communications, i.e. stop interrupt reception, and flush all - * queued buffers - */ void ath10k_htc_stop(struct ath10k_htc *htc) { spin_lock_bh(&htc->tx_lock); htc->stopped = true; spin_unlock_bh(&htc->tx_lock); - - ath10k_hif_stop(htc->ar); } /* registered target arrival callback from the HIF layer */ diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 69697af59ce..19c12cc8d66 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -22,7 +22,7 @@ #include "core.h" #include "debug.h" -static int ath10k_htt_htc_attach(struct ath10k_htt *htt) +int ath10k_htt_connect(struct ath10k_htt *htt) { struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; @@ -48,39 +48,14 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt) return 0; } -int ath10k_htt_attach(struct ath10k *ar) +int ath10k_htt_init(struct ath10k *ar) { struct ath10k_htt *htt = &ar->htt; - int ret; htt->ar = ar; htt->max_throughput_mbps = 800; /* - * Connect to HTC service. - * This has to be done before calling ath10k_htt_rx_attach, - * since ath10k_htt_rx_attach involves sending a rx ring configure - * message to the target. - */ - ret = ath10k_htt_htc_attach(htt); - if (ret) { - ath10k_err("could not attach htt htc (%d)\n", ret); - goto err_htc_attach; - } - - ret = ath10k_htt_tx_attach(htt); - if (ret) { - ath10k_err("could not attach htt tx (%d)\n", ret); - goto err_htc_attach; - } - - ret = ath10k_htt_rx_attach(htt); - if (ret) { - ath10k_err("could not attach htt rx (%d)\n", ret); - goto err_rx_attach; - } - - /* * Prefetch enough data to satisfy target * classification engine. * This is for LL chips. HL chips will probably @@ -93,11 +68,6 @@ int ath10k_htt_attach(struct ath10k *ar) 2; /* ip4 dscp or ip6 priority */ return 0; - -err_rx_attach: - ath10k_htt_tx_detach(htt); -err_htc_attach: - return ret; } #define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ) @@ -117,7 +87,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt) return 0; } -int ath10k_htt_attach_target(struct ath10k_htt *htt) +int ath10k_htt_setup(struct ath10k_htt *htt) { int status; @@ -140,9 +110,3 @@ int ath10k_htt_attach_target(struct ath10k_htt *htt) return ath10k_htt_send_rx_ring_cfg_ll(htt); } - -void ath10k_htt_detach(struct ath10k_htt *htt) -{ - ath10k_htt_rx_detach(htt); - ath10k_htt_tx_detach(htt); -} diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index b93ae355bc0..9a263462c79 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -20,6 +20,8 @@ #include <linux/bug.h> #include <linux/interrupt.h> +#include <linux/dmapool.h> +#include <net/mac80211.h> #include "htc.h" #include "rx_desc.h" @@ -1171,20 +1173,12 @@ struct htt_peer_unmap_event { u16 peer_id; }; -struct htt_rx_info { - struct sk_buff *skb; - enum htt_rx_mpdu_status status; - enum htt_rx_mpdu_encrypt_type encrypt_type; - s8 signal; - struct { - u8 info0; - u32 info1; - u32 info2; - } rate; - bool fcs_err; - bool amsdu_more; - bool mic_err; -}; +struct ath10k_htt_txbuf { + struct htt_data_tx_desc_frag frags[2]; + struct ath10k_htc_hdr htc_hdr; + struct htt_cmd_hdr cmd_hdr; + struct htt_data_tx_desc cmd_tx; +} __packed; struct ath10k_htt { struct ath10k *ar; @@ -1267,11 +1261,21 @@ struct ath10k_htt { struct sk_buff **pending_tx; unsigned long *used_msdu_ids; /* bitmap */ wait_queue_head_t empty_tx_wq; + struct dma_pool *tx_pool; /* set if host-fw communication goes haywire * used to avoid further failures */ bool rx_confused; struct tasklet_struct rx_replenish_task; + + /* This is used to group tx/rx completions separately and process them + * in batches to reduce cache stalls */ + struct tasklet_struct txrx_compl_task; + struct sk_buff_head tx_compl_q; + struct sk_buff_head rx_compl_q; + + /* rx_status template */ + struct ieee80211_rx_status rx_status; }; #define RX_HTT_HDR_STATUS_LEN 64 @@ -1324,14 +1328,16 @@ struct htt_rx_desc { #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) -int ath10k_htt_attach(struct ath10k *ar); -int ath10k_htt_attach_target(struct ath10k_htt *htt); -void ath10k_htt_detach(struct ath10k_htt *htt); +int ath10k_htt_connect(struct ath10k_htt *htt); +int ath10k_htt_init(struct ath10k *ar); +int ath10k_htt_setup(struct ath10k_htt *htt); + +int ath10k_htt_tx_alloc(struct ath10k_htt *htt); +void ath10k_htt_tx_free(struct ath10k_htt *htt); + +int ath10k_htt_rx_alloc(struct ath10k_htt *htt); +void ath10k_htt_rx_free(struct ath10k_htt *htt); -int ath10k_htt_tx_attach(struct ath10k_htt *htt); -void ath10k_htt_tx_detach(struct ath10k_htt *htt); -int ath10k_htt_rx_attach(struct ath10k_htt *htt); -void ath10k_htt_rx_detach(struct ath10k_htt *htt); void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb); void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); @@ -1343,4 +1349,5 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id); int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *); int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *); + #endif diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index fe8bd1b59f0..eebc860c365 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -43,7 +43,7 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); - +static void ath10k_htt_txrx_compl_task(unsigned long ptr); static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt) { @@ -225,31 +225,34 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg) ath10k_htt_rx_msdu_buff_replenish(htt); } -static unsigned ath10k_htt_rx_ring_elems(struct ath10k_htt *htt) +static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt) { - return (__le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr) - - htt->rx_ring.sw_rd_idx.msdu_payld) & htt->rx_ring.size_mask; + struct sk_buff *skb; + int i; + + for (i = 0; i < htt->rx_ring.size; i++) { + skb = htt->rx_ring.netbufs_ring[i]; + if (!skb) + continue; + + dma_unmap_single(htt->ar->dev, ATH10K_SKB_CB(skb)->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + htt->rx_ring.netbufs_ring[i] = NULL; + } } -void ath10k_htt_rx_detach(struct ath10k_htt *htt) +void ath10k_htt_rx_free(struct ath10k_htt *htt) { - int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld; - del_timer_sync(&htt->rx_ring.refill_retry_timer); tasklet_kill(&htt->rx_replenish_task); + tasklet_kill(&htt->txrx_compl_task); - while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) { - struct sk_buff *skb = - htt->rx_ring.netbufs_ring[sw_rd_idx]; - struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); + skb_queue_purge(&htt->tx_compl_q); + skb_queue_purge(&htt->rx_compl_q); - dma_unmap_single(htt->ar->dev, cb->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - dev_kfree_skb_any(htt->rx_ring.netbufs_ring[sw_rd_idx]); - sw_rd_idx++; - sw_rd_idx &= htt->rx_ring.size_mask; - } + ath10k_htt_rx_ring_clean_up(htt); dma_free_coherent(htt->ar->dev, (htt->rx_ring.size * @@ -270,20 +273,22 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) int idx; struct sk_buff *msdu; - spin_lock_bh(&htt->rx_ring.lock); + lockdep_assert_held(&htt->rx_ring.lock); - if (ath10k_htt_rx_ring_elems(htt) == 0) - ath10k_warn("htt rx ring is empty!\n"); + if (htt->rx_ring.fill_cnt == 0) { + ath10k_warn("tried to pop sk_buff from an empty rx ring\n"); + return NULL; + } idx = htt->rx_ring.sw_rd_idx.msdu_payld; msdu = htt->rx_ring.netbufs_ring[idx]; + htt->rx_ring.netbufs_ring[idx] = NULL; idx++; idx &= htt->rx_ring.size_mask; htt->rx_ring.sw_rd_idx.msdu_payld = idx; htt->rx_ring.fill_cnt--; - spin_unlock_bh(&htt->rx_ring.lock); return msdu; } @@ -298,6 +303,7 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) } } +/* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, u8 **fw_desc, int *fw_desc_len, struct sk_buff **head_msdu, @@ -307,12 +313,11 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, struct sk_buff *msdu; struct htt_rx_desc *rx_desc; - if (ath10k_htt_rx_ring_elems(htt) == 0) - ath10k_warn("htt rx ring is empty!\n"); + lockdep_assert_held(&htt->rx_ring.lock); if (htt->rx_confused) { ath10k_warn("htt is confused. refusing rx\n"); - return 0; + return -1; } msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt); @@ -324,7 +329,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ", msdu->data, msdu->len + skb_tailroom(msdu)); rx_desc = (struct htt_rx_desc *)msdu->data; @@ -417,8 +422,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, next->len + skb_tailroom(next), DMA_FROM_DEVICE); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", - next->data, + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, + "htt rx chained: ", next->data, next->len + skb_tailroom(next)); skb_trim(next, 0); @@ -430,12 +435,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_chaining = 1; } - if (msdu_len > 0) { - /* This may suggest FW bug? */ - ath10k_warn("htt rx msdu len not consumed (%d)\n", - msdu_len); - } - last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & RX_MSDU_END_INFO0_LAST_MSDU; @@ -450,6 +449,9 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, } *tail_msdu = msdu; + if (*head_msdu == NULL) + msdu_chaining = -1; + /* * Don't refill the ring yet. * @@ -472,7 +474,7 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr) ath10k_htt_rx_msdu_buff_replenish(htt); } -int ath10k_htt_rx_attach(struct ath10k_htt *htt) +int ath10k_htt_rx_alloc(struct ath10k_htt *htt) { dma_addr_t paddr; void *vaddr; @@ -498,7 +500,7 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt) htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt); htt->rx_ring.netbufs_ring = - kmalloc(htt->rx_ring.size * sizeof(struct sk_buff *), + kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *), GFP_KERNEL); if (!htt->rx_ring.netbufs_ring) goto err_netbuf; @@ -535,6 +537,12 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt) tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task, (unsigned long)htt); + skb_queue_head_init(&htt->tx_compl_q); + skb_queue_head_init(&htt->rx_compl_q); + + tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task, + (unsigned long)htt); + ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", htt->rx_ring.size, htt->rx_ring.fill_level); return 0; @@ -638,12 +646,216 @@ struct amsdu_subframe_hdr { __be16 len; } __packed; +static const u8 rx_legacy_rate_idx[] = { + 3, /* 0x00 - 11Mbps */ + 2, /* 0x01 - 5.5Mbps */ + 1, /* 0x02 - 2Mbps */ + 0, /* 0x03 - 1Mbps */ + 3, /* 0x04 - 11Mbps */ + 2, /* 0x05 - 5.5Mbps */ + 1, /* 0x06 - 2Mbps */ + 0, /* 0x07 - 1Mbps */ + 10, /* 0x08 - 48Mbps */ + 8, /* 0x09 - 24Mbps */ + 6, /* 0x0A - 12Mbps */ + 4, /* 0x0B - 6Mbps */ + 11, /* 0x0C - 54Mbps */ + 9, /* 0x0D - 36Mbps */ + 7, /* 0x0E - 18Mbps */ + 5, /* 0x0F - 9Mbps */ +}; + +static void ath10k_htt_rx_h_rates(struct ath10k *ar, + enum ieee80211_band band, + u8 info0, u32 info1, u32 info2, + struct ieee80211_rx_status *status) +{ + u8 cck, rate, rate_idx, bw, sgi, mcs, nss; + u8 preamble = 0; + + /* Check if valid fields */ + if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) + return; + + preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); + + switch (preamble) { + case HTT_RX_LEGACY: + cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; + rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); + rate_idx = 0; + + if (rate < 0x08 || rate > 0x0F) + break; + + switch (band) { + case IEEE80211_BAND_2GHZ: + if (cck) + rate &= ~BIT(3); + rate_idx = rx_legacy_rate_idx[rate]; + break; + case IEEE80211_BAND_5GHZ: + rate_idx = rx_legacy_rate_idx[rate]; + /* We are using same rate table registering + HW - ath10k_rates[]. In case of 5GHz skip + CCK rates, so -4 here */ + rate_idx -= 4; + break; + default: + break; + } + + status->rate_idx = rate_idx; + break; + case HTT_RX_HT: + case HTT_RX_HT_WITH_TXBF: + /* HT-SIG - Table 20-11 in info1 and info2 */ + mcs = info1 & 0x1F; + nss = mcs >> 3; + bw = (info1 >> 7) & 1; + sgi = (info2 >> 7) & 1; + + status->rate_idx = mcs; + status->flag |= RX_FLAG_HT; + if (sgi) + status->flag |= RX_FLAG_SHORT_GI; + if (bw) + status->flag |= RX_FLAG_40MHZ; + break; + case HTT_RX_VHT: + case HTT_RX_VHT_WITH_TXBF: + /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 + TODO check this */ + mcs = (info2 >> 4) & 0x0F; + nss = ((info1 >> 10) & 0x07) + 1; + bw = info1 & 3; + sgi = info2 & 1; + + status->rate_idx = mcs; + status->vht_nss = nss; + + if (sgi) + status->flag |= RX_FLAG_SHORT_GI; + + switch (bw) { + /* 20MHZ */ + case 0: + break; + /* 40MHZ */ + case 1: + status->flag |= RX_FLAG_40MHZ; + break; + /* 80MHZ */ + case 2: + status->vht_flag |= RX_VHT_FLAG_80MHZ; + } + + status->flag |= RX_FLAG_VHT; + break; + default: + break; + } +} + +static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt, + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb, + enum htt_rx_mpdu_encrypt_type enctype, + enum rx_msdu_decap_format fmt, + bool dot11frag) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + rx_status->flag &= ~(RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED); + + if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) + return; + + /* + * There's no explicit rx descriptor flag to indicate whether a given + * frame has been decrypted or not. We're forced to use the decap + * format as an implicit indication. However fragmentation rx is always + * raw and it probably never reports undecrypted raws. + * + * This makes sure sniffed frames are reported as-is without stripping + * the protected flag. + */ + if (fmt == RX_MSDU_DECAP_RAW && !dot11frag) + return; + + rx_status->flag |= RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; + hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) & + ~IEEE80211_FCTL_PROTECTED); +} + +static bool ath10k_htt_rx_h_channel(struct ath10k *ar, + struct ieee80211_rx_status *status) +{ + struct ieee80211_channel *ch; + + spin_lock_bh(&ar->data_lock); + ch = ar->scan_channel; + if (!ch) + ch = ar->rx_channel; + spin_unlock_bh(&ar->data_lock); + + if (!ch) + return false; + + status->band = ch->band; + status->freq = ch->center_freq; + + return true; +} + +static void ath10k_process_rx(struct ath10k *ar, + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *status; + + status = IEEE80211_SKB_RXCB(skb); + *status = *rx_status; + + ath10k_dbg(ATH10K_DBG_DATA, + "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n", + skb, + skb->len, + status->flag == 0 ? "legacy" : "", + status->flag & RX_FLAG_HT ? "ht" : "", + status->flag & RX_FLAG_VHT ? "vht" : "", + status->flag & RX_FLAG_40MHZ ? "40" : "", + status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "", + status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", + status->rate_idx, + status->vht_nss, + status->freq, + status->band, status->flag, + !!(status->flag & RX_FLAG_FAILED_FCS_CRC), + !!(status->flag & RX_FLAG_MMIC_ERROR)); + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", + skb->data, skb->len); + + ieee80211_rx(ar->hw, skb); +} + +static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) +{ + /* nwifi header is padded to 4 bytes. this fixes 4addr rx */ + return round_up(ieee80211_hdrlen(hdr->frame_control), 4); +} + static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, - struct htt_rx_info *info) + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb_in) { struct htt_rx_desc *rxd; + struct sk_buff *skb = skb_in; struct sk_buff *first; - struct sk_buff *skb = info->skb; enum rx_msdu_decap_format fmt; enum htt_rx_mpdu_encrypt_type enctype; struct ieee80211_hdr *hdr; @@ -687,7 +899,7 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, case RX_MSDU_DECAP_NATIVE_WIFI: /* pull decapped header and copy DA */ hdr = (struct ieee80211_hdr *)skb->data; - hdr_len = ieee80211_hdrlen(hdr->frame_control); + hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN); skb_pull(skb, hdr_len); @@ -724,24 +936,28 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, break; } - info->skb = skb; - info->encrypt_type = enctype; + skb_in = skb; + ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt, + false); skb = skb->next; - info->skb->next = NULL; + skb_in->next = NULL; if (skb) - info->amsdu_more = true; + rx_status->flag |= RX_FLAG_AMSDU_MORE; + else + rx_status->flag &= ~RX_FLAG_AMSDU_MORE; - ath10k_process_rx(htt->ar, info); + ath10k_process_rx(htt->ar, rx_status, skb_in); } /* FIXME: It might be nice to re-assemble the A-MSDU when there's a * monitor interface active for sniffing purposes. */ } -static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) +static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, + struct ieee80211_rx_status *rx_status, + struct sk_buff *skb) { - struct sk_buff *skb = info->skb; struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; enum rx_msdu_decap_format fmt; @@ -751,7 +967,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) /* This shouldn't happen. If it does than it may be a FW bug. */ if (skb->next) { - ath10k_warn("received chained non A-MSDU frame\n"); + ath10k_warn("htt rx received chained non A-MSDU frame\n"); ath10k_htt_rx_free_msdu_chain(skb->next); skb->next = NULL; } @@ -774,7 +990,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) case RX_MSDU_DECAP_NATIVE_WIFI: /* Pull decapped header */ hdr = (struct ieee80211_hdr *)skb->data; - hdr_len = ieee80211_hdrlen(hdr->frame_control); + hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); skb_pull(skb, hdr_len); /* Push original header */ @@ -804,52 +1020,9 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) break; } - info->skb = skb; - info->encrypt_type = enctype; + ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt, false); - ath10k_process_rx(htt->ar, info); -} - -static bool ath10k_htt_rx_has_decrypt_err(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - u32 flags; - - rxd = (void *)skb->data - sizeof(*rxd); - flags = __le32_to_cpu(rxd->attention.flags); - - if (flags & RX_ATTENTION_FLAGS_DECRYPT_ERR) - return true; - - return false; -} - -static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - u32 flags; - - rxd = (void *)skb->data - sizeof(*rxd); - flags = __le32_to_cpu(rxd->attention.flags); - - if (flags & RX_ATTENTION_FLAGS_FCS_ERR) - return true; - - return false; -} - -static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - u32 flags; - - rxd = (void *)skb->data - sizeof(*rxd); - flags = __le32_to_cpu(rxd->attention.flags); - - if (flags & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) - return true; - - return false; + ath10k_process_rx(htt->ar, rx_status, skb); } static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) @@ -883,18 +1056,123 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) return CHECKSUM_UNNECESSARY; } +static int ath10k_unchain_msdu(struct sk_buff *msdu_head) +{ + struct sk_buff *next = msdu_head->next; + struct sk_buff *to_free = next; + int space; + int total_len = 0; + + /* TODO: Might could optimize this by using + * skb_try_coalesce or similar method to + * decrease copying, or maybe get mac80211 to + * provide a way to just receive a list of + * skb? + */ + + msdu_head->next = NULL; + + /* Allocate total length all at once. */ + while (next) { + total_len += next->len; + next = next->next; + } + + space = total_len - skb_tailroom(msdu_head); + if ((space > 0) && + (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) { + /* TODO: bump some rx-oom error stat */ + /* put it back together so we can free the + * whole list at once. + */ + msdu_head->next = to_free; + return -1; + } + + /* Walk list again, copying contents into + * msdu_head + */ + next = to_free; + while (next) { + skb_copy_from_linear_data(next, skb_put(msdu_head, next->len), + next->len); + next = next->next; + } + + /* If here, we have consolidated skb. Free the + * fragments and pass the main skb on up the + * stack. + */ + ath10k_htt_rx_free_msdu_chain(to_free); + return 0; +} + +static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, + struct sk_buff *head, + enum htt_rx_mpdu_status status, + bool channel_set, + u32 attention) +{ + if (head->len == 0) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx dropping due to zero-len\n"); + return false; + } + + if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx dropping due to decrypt-err\n"); + return false; + } + + if (!channel_set) { + ath10k_warn("no channel configured; ignoring frame!\n"); + return false; + } + + /* Skip mgmt frames while we handle this in WMI */ + if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || + attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { + ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); + return false; + } + + if (status != HTT_RX_IND_MPDU_STATUS_OK && + status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && + status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && + !htt->ar->monitor_started) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx ignoring frame w/ status %d\n", + status); + return false; + } + + if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx CAC running\n"); + return false; + } + + return true; +} + static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct htt_rx_indication *rx) { - struct htt_rx_info info; + struct ieee80211_rx_status *rx_status = &htt->rx_status; struct htt_rx_indication_mpdu_range *mpdu_ranges; + struct htt_rx_desc *rxd; + enum htt_rx_mpdu_status status; struct ieee80211_hdr *hdr; int num_mpdu_ranges; + u32 attention; int fw_desc_len; u8 *fw_desc; + bool channel_set; int i, j; + int ret; - memset(&info, 0, sizeof(info)); + lockdep_assert_held(&htt->rx_ring.lock); fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); fw_desc = (u8 *)&rx->fw_desc; @@ -903,91 +1181,90 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); + /* Fill this once, while this is per-ppdu */ + if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) { + memset(rx_status, 0, sizeof(*rx_status)); + rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR + + rx->ppdu.combined_rssi; + } + + if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { + /* TSF available only in 32-bit */ + rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff; + rx_status->flag |= RX_FLAG_MACTIME_END; + } + + channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status); + + if (channel_set) { + ath10k_htt_rx_h_rates(htt->ar, rx_status->band, + rx->ppdu.info0, + __le32_to_cpu(rx->ppdu.info1), + __le32_to_cpu(rx->ppdu.info2), + rx_status); + } + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", rx, sizeof(*rx) + (sizeof(struct htt_rx_indication_mpdu_range) * num_mpdu_ranges)); for (i = 0; i < num_mpdu_ranges; i++) { - info.status = mpdu_ranges[i].mpdu_range_status; + status = mpdu_ranges[i].mpdu_range_status; for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { struct sk_buff *msdu_head, *msdu_tail; - enum htt_rx_mpdu_status status; - int msdu_chaining; msdu_head = NULL; msdu_tail = NULL; - msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, - &fw_desc, - &fw_desc_len, - &msdu_head, - &msdu_tail); - - if (!msdu_head) { - ath10k_warn("htt rx no data!\n"); - continue; - } - - if (msdu_head->len == 0) { - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx dropping due to zero-len\n"); + ret = ath10k_htt_rx_amsdu_pop(htt, + &fw_desc, + &fw_desc_len, + &msdu_head, + &msdu_tail); + + if (ret < 0) { + ath10k_warn("failed to pop amsdu from htt rx ring %d\n", + ret); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } - if (ath10k_htt_rx_has_decrypt_err(msdu_head)) { - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } + rxd = container_of((void *)msdu_head->data, + struct htt_rx_desc, + msdu_payload); + attention = __le32_to_cpu(rxd->attention.flags); - status = info.status; - - /* Skip mgmt frames while we handle this in WMI */ - if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) { + if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, + status, + channel_set, + attention)) { ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } - if (status != HTT_RX_IND_MPDU_STATUS_OK && - status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && - !htt->ar->monitor_enabled) { - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx ignoring frame w/ status %d\n", - status); + if (ret > 0 && + ath10k_unchain_msdu(msdu_head) < 0) { ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } - if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - /* FIXME: we do not support chaining yet. - * this needs investigation */ - if (msdu_chaining) { - ath10k_warn("msdu_chaining is true\n"); - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - info.skb = msdu_head; - info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); - info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head); - info.signal = ATH10K_DEFAULT_NOISE_FLOOR; - info.signal += rx->ppdu.combined_rssi; + if (attention & RX_ATTENTION_FLAGS_FCS_ERR) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + else + rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC; - info.rate.info0 = rx->ppdu.info0; - info.rate.info1 = __le32_to_cpu(rx->ppdu.info1); - info.rate.info2 = __le32_to_cpu(rx->ppdu.info2); + if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) + rx_status->flag |= RX_FLAG_MMIC_ERROR; + else + rx_status->flag &= ~RX_FLAG_MMIC_ERROR; hdr = ath10k_htt_rx_skb_get_hdr(msdu_head); if (ath10k_htt_rx_hdr_is_amsdu(hdr)) - ath10k_htt_rx_amsdu(htt, &info); + ath10k_htt_rx_amsdu(htt, rx_status, msdu_head); else - ath10k_htt_rx_msdu(htt, &info); + ath10k_htt_rx_msdu(htt, rx_status, msdu_head); } } @@ -998,11 +1275,12 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, struct htt_rx_fragment_indication *frag) { struct sk_buff *msdu_head, *msdu_tail; + enum htt_rx_mpdu_encrypt_type enctype; struct htt_rx_desc *rxd; enum rx_msdu_decap_format fmt; - struct htt_rx_info info = {}; + struct ieee80211_rx_status *rx_status = &htt->rx_status; struct ieee80211_hdr *hdr; - int msdu_chaining; + int ret; bool tkip_mic_err; bool decrypt_err; u8 *fw_desc; @@ -1014,23 +1292,23 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, msdu_head = NULL; msdu_tail = NULL; - msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, - &msdu_head, &msdu_tail); - ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); + spin_lock_bh(&htt->rx_ring.lock); + ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, + &msdu_head, &msdu_tail); + spin_unlock_bh(&htt->rx_ring.lock); - if (!msdu_head) { - ath10k_warn("htt rx frag no data\n"); - return; - } + ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); - if (msdu_chaining || msdu_head != msdu_tail) { - ath10k_warn("aggregation with fragmentation?!\n"); + if (ret) { + ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n", + ret); ath10k_htt_rx_free_msdu_chain(msdu_head); return; } /* FIXME: implement signal strength */ + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; hdr = (struct ieee80211_hdr *)msdu_head->data; rxd = (void *)msdu_head->data - sizeof(*rxd); @@ -1047,57 +1325,55 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, goto end; } - info.skb = msdu_head; - info.status = HTT_RX_IND_MPDU_STATUS_OK; - info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0), - RX_MPDU_START_INFO0_ENCRYPT_TYPE); - info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb); + enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), + RX_MPDU_START_INFO0_ENCRYPT_TYPE); + ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype, fmt, + true); + msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); - if (tkip_mic_err) { + if (tkip_mic_err) ath10k_warn("tkip mic error\n"); - info.status = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR; - } if (decrypt_err) { ath10k_warn("decryption err in fragmented rx\n"); - dev_kfree_skb_any(info.skb); + dev_kfree_skb_any(msdu_head); goto end; } - if (info.encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) { + if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) { hdrlen = ieee80211_hdrlen(hdr->frame_control); - paramlen = ath10k_htt_rx_crypto_param_len(info.encrypt_type); + paramlen = ath10k_htt_rx_crypto_param_len(enctype); /* It is more efficient to move the header than the payload */ - memmove((void *)info.skb->data + paramlen, - (void *)info.skb->data, + memmove((void *)msdu_head->data + paramlen, + (void *)msdu_head->data, hdrlen); - skb_pull(info.skb, paramlen); - hdr = (struct ieee80211_hdr *)info.skb->data; + skb_pull(msdu_head, paramlen); + hdr = (struct ieee80211_hdr *)msdu_head->data; } /* remove trailing FCS */ trim = 4; /* remove crypto trailer */ - trim += ath10k_htt_rx_crypto_tail_len(info.encrypt_type); + trim += ath10k_htt_rx_crypto_tail_len(enctype); /* last fragment of TKIP frags has MIC */ if (!ieee80211_has_morefrags(hdr->frame_control) && - info.encrypt_type == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) + enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) trim += 8; - if (trim > info.skb->len) { + if (trim > msdu_head->len) { ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n"); - dev_kfree_skb_any(info.skb); + dev_kfree_skb_any(msdu_head); goto end; } - skb_trim(info.skb, info.skb->len - trim); + skb_trim(msdu_head, msdu_head->len - trim); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt frag mpdu: ", - info.skb->data, info.skb->len); - ath10k_process_rx(htt->ar, &info); + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", + msdu_head->data, msdu_head->len); + ath10k_process_rx(htt->ar, rx_status, msdu_head); end: if (fw_desc_len > 0) { @@ -1107,6 +1383,45 @@ end: } } +static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, + struct sk_buff *skb) +{ + struct ath10k_htt *htt = &ar->htt; + struct htt_resp *resp = (struct htt_resp *)skb->data; + struct htt_tx_done tx_done = {}; + int status = MS(resp->data_tx_completion.flags, HTT_DATA_TX_STATUS); + __le16 msdu_id; + int i; + + lockdep_assert_held(&htt->tx_lock); + + switch (status) { + case HTT_DATA_TX_STATUS_NO_ACK: + tx_done.no_ack = true; + break; + case HTT_DATA_TX_STATUS_OK: + break; + case HTT_DATA_TX_STATUS_DISCARD: + case HTT_DATA_TX_STATUS_POSTPONE: + case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL: + tx_done.discard = true; + break; + default: + ath10k_warn("unhandled tx completion status %d\n", status); + tx_done.discard = true; + break; + } + + ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", + resp->data_tx_completion.num_msdus); + + for (i = 0; i < resp->data_tx_completion.num_msdus; i++) { + msdu_id = resp->data_tx_completion.msdus[i]; + tx_done.msdu_id = __le16_to_cpu(msdu_id); + ath10k_txrx_tx_unref(htt, &tx_done); + } +} + void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_htt *htt = &ar->htt; @@ -1116,7 +1431,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) if (!IS_ALIGNED((unsigned long)skb->data, 4)) ath10k_warn("unaligned htt message, expect trouble\n"); - ath10k_dbg(ATH10K_DBG_HTT, "HTT RX, msg_type: 0x%0X\n", + ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n", resp->hdr.msg_type); switch (resp->hdr.msg_type) { case HTT_T2H_MSG_TYPE_VERSION_CONF: { @@ -1125,10 +1440,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) complete(&htt->target_version_received); break; } - case HTT_T2H_MSG_TYPE_RX_IND: { - ath10k_htt_rx_handler(htt, &resp->rx_ind); - break; - } + case HTT_T2H_MSG_TYPE_RX_IND: + spin_lock_bh(&htt->rx_ring.lock); + __skb_queue_tail(&htt->rx_compl_q, skb); + spin_unlock_bh(&htt->rx_ring.lock); + tasklet_schedule(&htt->txrx_compl_task); + return; case HTT_T2H_MSG_TYPE_PEER_MAP: { struct htt_peer_map_event ev = { .vdev_id = resp->peer_map.vdev_id, @@ -1163,44 +1480,17 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } + spin_lock_bh(&htt->tx_lock); ath10k_txrx_tx_unref(htt, &tx_done); + spin_unlock_bh(&htt->tx_lock); break; } - case HTT_T2H_MSG_TYPE_TX_COMPL_IND: { - struct htt_tx_done tx_done = {}; - int status = MS(resp->data_tx_completion.flags, - HTT_DATA_TX_STATUS); - __le16 msdu_id; - int i; - - switch (status) { - case HTT_DATA_TX_STATUS_NO_ACK: - tx_done.no_ack = true; - break; - case HTT_DATA_TX_STATUS_OK: - break; - case HTT_DATA_TX_STATUS_DISCARD: - case HTT_DATA_TX_STATUS_POSTPONE: - case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL: - tx_done.discard = true; - break; - default: - ath10k_warn("unhandled tx completion status %d\n", - status); - tx_done.discard = true; - break; - } - - ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n", - resp->data_tx_completion.num_msdus); - - for (i = 0; i < resp->data_tx_completion.num_msdus; i++) { - msdu_id = resp->data_tx_completion.msdus[i]; - tx_done.msdu_id = __le16_to_cpu(msdu_id); - ath10k_txrx_tx_unref(htt, &tx_done); - } - break; - } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + spin_lock_bh(&htt->tx_lock); + __skb_queue_tail(&htt->tx_compl_q, skb); + spin_unlock_bh(&htt->tx_lock); + tasklet_schedule(&htt->txrx_compl_task); + return; case HTT_T2H_MSG_TYPE_SEC_IND: { struct ath10k *ar = htt->ar; struct htt_security_indication *ev = &resp->security_indication; @@ -1240,3 +1530,25 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) /* Free the indication buffer */ dev_kfree_skb_any(skb); } + +static void ath10k_htt_txrx_compl_task(unsigned long ptr) +{ + struct ath10k_htt *htt = (struct ath10k_htt *)ptr; + struct htt_resp *resp; + struct sk_buff *skb; + + spin_lock_bh(&htt->tx_lock); + while ((skb = __skb_dequeue(&htt->tx_compl_q))) { + ath10k_htt_rx_frm_tx_compl(htt->ar, skb); + dev_kfree_skb_any(skb); + } + spin_unlock_bh(&htt->tx_lock); + + spin_lock_bh(&htt->rx_ring.lock); + while ((skb = __skb_dequeue(&htt->rx_compl_q))) { + resp = (struct htt_resp *)skb->data; + ath10k_htt_rx_handler(htt, &resp->rx_ind); + dev_kfree_skb_any(skb); + } + spin_unlock_bh(&htt->rx_ring.lock); +} diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index f1d36d2d272..7064354d1f4 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -83,7 +83,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) __clear_bit(msdu_id, htt->used_msdu_ids); } -int ath10k_htt_tx_attach(struct ath10k_htt *htt) +int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { spin_lock_init(&htt->tx_lock); init_waitqueue_head(&htt->empty_tx_wq); @@ -109,17 +109,23 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt) return -ENOMEM; } + htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, + sizeof(struct ath10k_htt_txbuf), 4, 0); + if (!htt->tx_pool) { + kfree(htt->used_msdu_ids); + kfree(htt->pending_tx); + return -ENOMEM; + } + return 0; } -static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) +static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt) { struct htt_tx_done tx_done = {0}; int msdu_id; - /* No locks needed. Called after communication with the device has - * been stopped. */ - + spin_lock_bh(&htt->tx_lock); for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) { if (!test_bit(msdu_id, htt->used_msdu_ids)) continue; @@ -132,13 +138,15 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) ath10k_txrx_tx_unref(htt, &tx_done); } + spin_unlock_bh(&htt->tx_lock); } -void ath10k_htt_tx_detach(struct ath10k_htt *htt) +void ath10k_htt_tx_free(struct ath10k_htt *htt) { - ath10k_htt_tx_cleanup_pending(htt); + ath10k_htt_tx_free_pending(htt); kfree(htt->pending_tx); kfree(htt->used_msdu_ids); + dma_pool_destroy(htt->tx_pool); return; } @@ -334,7 +342,9 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) goto err_free_msdu_id; } - res = ath10k_skb_map(dev, msdu); + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, + DMA_TO_DEVICE); + res = dma_mapping_error(dev, skb_cb->paddr); if (res) goto err_free_txdesc; @@ -348,8 +358,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) memcpy(cmd->mgmt_tx.hdr, msdu->data, min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN)); - skb_cb->htt.frag_len = 0; - skb_cb->htt.pad_len = 0; + skb_cb->htt.txbuf = NULL; res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); if (res) @@ -358,7 +367,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) return 0; err_unmap_msdu: - ath10k_skb_unmap(dev, msdu); + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_txdesc: dev_kfree_skb_any(txdesc); err_free_msdu_id: @@ -375,19 +384,19 @@ err: int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { struct device *dev = htt->ar->dev; - struct htt_cmd *cmd; - struct htt_data_tx_desc_frag *tx_frags; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); - struct sk_buff *txdesc = NULL; - bool use_frags; - u8 vdev_id = ATH10K_SKB_CB(msdu)->vdev_id; - u8 tid; - int prefetch_len, desc_len; - int msdu_id = -1; + struct ath10k_hif_sg_item sg_items[2]; + struct htt_data_tx_desc_frag *frags; + u8 vdev_id = skb_cb->vdev_id; + u8 tid = skb_cb->htt.tid; + int prefetch_len; int res; - u8 flags0; - u16 flags1; + u8 flags0 = 0; + u16 msdu_id, flags1 = 0; + dma_addr_t paddr; + u32 frags_paddr; + bool use_frags; res = ath10k_htt_tx_inc_pending(htt); if (res) @@ -406,114 +415,120 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); - desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len; - - txdesc = ath10k_htc_alloc_skb(desc_len); - if (!txdesc) { - res = -ENOMEM; - goto err_free_msdu_id; - } - /* Since HTT 3.0 there is no separate mgmt tx command. However in case * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx * fragment list host driver specifies directly frame pointer. */ use_frags = htt->target_version_major < 3 || !ieee80211_is_mgmt(hdr->frame_control); - if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { - ath10k_warn("htt alignment check failed. dropping packet.\n"); - res = -EIO; - goto err_free_txdesc; - } + skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, + &paddr); + if (!skb_cb->htt.txbuf) + goto err_free_msdu_id; + skb_cb->htt.txbuf_paddr = paddr; - if (use_frags) { - skb_cb->htt.frag_len = sizeof(*tx_frags) * 2; - skb_cb->htt.pad_len = (unsigned long)msdu->data - - round_down((unsigned long)msdu->data, 4); + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, + DMA_TO_DEVICE); + res = dma_mapping_error(dev, skb_cb->paddr); + if (res) + goto err_free_txbuf; - skb_push(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); - } else { - skb_cb->htt.frag_len = 0; - skb_cb->htt.pad_len = 0; - } + if (likely(use_frags)) { + frags = skb_cb->htt.txbuf->frags; - res = ath10k_skb_map(dev, msdu); - if (res) - goto err_pull_txfrag; - - if (use_frags) { - dma_sync_single_for_cpu(dev, skb_cb->paddr, msdu->len, - DMA_TO_DEVICE); - - /* tx fragment list must be terminated with zero-entry */ - tx_frags = (struct htt_data_tx_desc_frag *)msdu->data; - tx_frags[0].paddr = __cpu_to_le32(skb_cb->paddr + - skb_cb->htt.frag_len + - skb_cb->htt.pad_len); - tx_frags[0].len = __cpu_to_le32(msdu->len - - skb_cb->htt.frag_len - - skb_cb->htt.pad_len); - tx_frags[1].paddr = __cpu_to_le32(0); - tx_frags[1].len = __cpu_to_le32(0); - - dma_sync_single_for_device(dev, skb_cb->paddr, msdu->len, - DMA_TO_DEVICE); - } + frags[0].paddr = __cpu_to_le32(skb_cb->paddr); + frags[0].len = __cpu_to_le32(msdu->len); + frags[1].paddr = 0; + frags[1].len = 0; - ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n", - (unsigned long long) ATH10K_SKB_CB(msdu)->paddr); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", - msdu->data, msdu->len); + flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, + HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - skb_put(txdesc, desc_len); - cmd = (struct htt_cmd *)txdesc->data; + frags_paddr = skb_cb->htt.txbuf_paddr; + } else { + flags0 |= SM(ATH10K_HW_TXRX_MGMT, + HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - tid = ATH10K_SKB_CB(msdu)->htt.tid; + frags_paddr = skb_cb->paddr; + } - ath10k_dbg(ATH10K_DBG_HTT, "htt data tx using tid %hhu\n", tid); + /* Normally all commands go through HTC which manages tx credits for + * each endpoint and notifies when tx is completed. + * + * HTT endpoint is creditless so there's no need to care about HTC + * flags. In that case it is trivial to fill the HTC header here. + * + * MSDU transmission is considered completed upon HTT event. This + * implies no relevant resources can be freed until after the event is + * received. That's why HTC tx completion handler itself is ignored by + * setting NULL to transfer_context for all sg items. + * + * There is simply no point in pushing HTT TX_FRM through HTC tx path + * as it's a waste of resources. By bypassing HTC it is possible to + * avoid extra memory allocations, compress data structures and thus + * improve performance. */ + + skb_cb->htt.txbuf->htc_hdr.eid = htt->eid; + skb_cb->htt.txbuf->htc_hdr.len = __cpu_to_le16( + sizeof(skb_cb->htt.txbuf->cmd_hdr) + + sizeof(skb_cb->htt.txbuf->cmd_tx) + + prefetch_len); + skb_cb->htt.txbuf->htc_hdr.flags = 0; - flags0 = 0; if (!ieee80211_has_protected(hdr->frame_control)) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; - flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - if (use_frags) - flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, - HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - else - flags0 |= SM(ATH10K_HW_TXRX_MGMT, - HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); + flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - flags1 = 0; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; - cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; - cmd->data_tx.flags0 = flags0; - cmd->data_tx.flags1 = __cpu_to_le16(flags1); - cmd->data_tx.len = __cpu_to_le16(msdu->len - - skb_cb->htt.frag_len - - skb_cb->htt.pad_len); - cmd->data_tx.id = __cpu_to_le16(msdu_id); - cmd->data_tx.frags_paddr = __cpu_to_le32(skb_cb->paddr); - cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); - - memcpy(cmd->data_tx.prefetch, hdr, prefetch_len); + skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; + skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; + skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); + skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); + skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); + skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); + skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); + + ath10k_dbg(ATH10K_DBG_HTT, + "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n", + flags0, flags1, msdu->len, msdu_id, frags_paddr, + (u32)skb_cb->paddr, vdev_id, tid); + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", + msdu->data, msdu->len); - res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); + sg_items[0].transfer_id = 0; + sg_items[0].transfer_context = NULL; + sg_items[0].vaddr = &skb_cb->htt.txbuf->htc_hdr; + sg_items[0].paddr = skb_cb->htt.txbuf_paddr + + sizeof(skb_cb->htt.txbuf->frags); + sg_items[0].len = sizeof(skb_cb->htt.txbuf->htc_hdr) + + sizeof(skb_cb->htt.txbuf->cmd_hdr) + + sizeof(skb_cb->htt.txbuf->cmd_tx); + + sg_items[1].transfer_id = 0; + sg_items[1].transfer_context = NULL; + sg_items[1].vaddr = msdu->data; + sg_items[1].paddr = skb_cb->paddr; + sg_items[1].len = prefetch_len; + + res = ath10k_hif_tx_sg(htt->ar, + htt->ar->htc.endpoint[htt->eid].ul_pipe_id, + sg_items, ARRAY_SIZE(sg_items)); if (res) goto err_unmap_msdu; return 0; err_unmap_msdu: - ath10k_skb_unmap(dev, msdu); -err_pull_txfrag: - skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); -err_free_txdesc: - dev_kfree_skb_any(txdesc); + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); +err_free_txbuf: + dma_pool_free(htt->tx_pool, + skb_cb->htt.txbuf, + skb_cb->htt.txbuf_paddr); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); htt->pending_tx[msdu_id] = NULL; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index f1505a25d81..007e855f4ba 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -28,6 +28,7 @@ #define QCA988X_HW_2_0_CHIP_ID_REV 0x2 #define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0" #define QCA988X_HW_2_0_FW_FILE "firmware.bin" +#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin" #define QCA988X_HW_2_0_OTP_FILE "otp.bin" #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 @@ -205,8 +206,11 @@ enum ath10k_mcast2ucast_mode { #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 #define PCIE_LOCAL_BASE_ADDRESS 0x00080000 +#define SOC_RESET_CONTROL_ADDRESS 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000 #define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 #define SOC_CPU_CLOCK_OFFSET 0x00000020 #define SOC_CPU_CLOCK_STANDARD_LSB 0 #define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 @@ -216,6 +220,8 @@ enum ath10k_mcast2ucast_mode { #define SOC_LPO_CAL_OFFSET 0x000000e0 #define SOC_LPO_CAL_ENABLE_LSB 20 #define SOC_LPO_CAL_ENABLE_MASK 0x00100000 +#define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 #define SOC_CHIP_ID_ADDRESS 0x000000ec #define SOC_CHIP_ID_REV_LSB 8 @@ -273,6 +279,7 @@ enum ath10k_mcast2ucast_mode { #define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CLR_ADDRESS 0x0014 #define SCRATCH_3_ADDRESS 0x0030 +#define CPU_INTR_ADDRESS 0x0010 /* Firmware indications to the Host via SCRATCH_3 register. */ #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 776e364eadc..a21080028c5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -54,7 +54,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif, switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: arg.key_cipher = WMI_CIPHER_AES_CCM; - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; + else + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; break; case WLAN_CIPHER_SUITE_TKIP: arg.key_cipher = WMI_CIPHER_TKIP; @@ -165,7 +168,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, first_errno = ret; if (ret) - ath10k_warn("could not remove peer wep key %d (%d)\n", + ath10k_warn("failed to remove peer wep key %d: %d\n", i, ret); peer->keys[i] = NULL; @@ -213,7 +216,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, first_errno = ret; if (ret) - ath10k_warn("could not remove key for %pM\n", addr); + ath10k_warn("failed to remove key for %pM: %d\n", + addr, ret); } return first_errno; @@ -323,13 +327,15 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) ret = ath10k_wmi_peer_create(ar, vdev_id, addr); if (ret) { - ath10k_warn("Failed to create wmi peer: %i\n", ret); + ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n", + addr, vdev_id, ret); return ret; } ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); if (ret) { - ath10k_warn("Failed to wait for created wmi peer: %i\n", ret); + ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n", + addr, vdev_id, ret); return ret; } spin_lock_bh(&ar->data_lock); @@ -339,6 +345,51 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) return 0; } +static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 param; + int ret; + + param = ar->wmi.pdev_param->sta_kickout_th; + ret = ath10k_wmi_pdev_set_param(ar, param, + ATH10K_KICKOUT_THRESHOLD); + if (ret) { + ath10k_warn("failed to set kickout threshold on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MIN_IDLE); + if (ret) { + ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MAX_IDLE); + if (ret) { + ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); + if (ret) { + ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) { struct ath10k *ar = arvif->ar; @@ -441,110 +492,35 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) return 0; } -static int ath10k_vdev_start(struct ath10k_vif *arvif) +static bool ath10k_monitor_is_enabled(struct ath10k *ar) { - struct ath10k *ar = arvif->ar; - struct ieee80211_conf *conf = &ar->hw->conf; - struct ieee80211_channel *channel = conf->chandef.chan; - struct wmi_vdev_start_request_arg arg = {}; - int ret = 0; - lockdep_assert_held(&ar->conf_mutex); - reinit_completion(&ar->vdev_setup_done); - - arg.vdev_id = arvif->vdev_id; - arg.dtim_period = arvif->dtim_period; - arg.bcn_intval = arvif->beacon_interval; - - arg.channel.freq = channel->center_freq; - - arg.channel.band_center_freq1 = conf->chandef.center_freq1; - - arg.channel.mode = chan_to_phymode(&conf->chandef); - - arg.channel.min_power = 0; - arg.channel.max_power = channel->max_power * 2; - arg.channel.max_reg_power = channel->max_reg_power * 2; - arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; - - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - arg.ssid = arvif->u.ap.ssid; - arg.ssid_len = arvif->u.ap.ssid_len; - arg.hidden_ssid = arvif->u.ap.hidden_ssid; - - /* For now allow DFS for AP mode */ - arg.channel.chan_radar = - !!(channel->flags & IEEE80211_CHAN_RADAR); - } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { - arg.ssid = arvif->vif->bss_conf.ssid; - arg.ssid_len = arvif->vif->bss_conf.ssid_len; - } - ath10k_dbg(ATH10K_DBG_MAC, - "mac vdev %d start center_freq %d phymode %s\n", - arg.vdev_id, arg.channel.freq, - ath10k_wmi_phymode_str(arg.channel.mode)); - - ret = ath10k_wmi_vdev_start(ar, &arg); - if (ret) { - ath10k_warn("WMI vdev start failed: ret %d\n", ret); - return ret; - } - - ret = ath10k_vdev_setup_sync(ar); - if (ret) { - ath10k_warn("vdev setup failed %d\n", ret); - return ret; - } - - return ret; -} - -static int ath10k_vdev_stop(struct ath10k_vif *arvif) -{ - struct ath10k *ar = arvif->ar; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - reinit_completion(&ar->vdev_setup_done); + "mac monitor refs: promisc %d monitor %d cac %d\n", + ar->promisc, ar->monitor, + test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)); - ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); - if (ret) { - ath10k_warn("WMI vdev stop failed: ret %d\n", ret); - return ret; - } - - ret = ath10k_vdev_setup_sync(ar); - if (ret) { - ath10k_warn("vdev setup failed %d\n", ret); - return ret; - } - - return ret; + return ar->promisc || ar->monitor || + test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); } -static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) +static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { - struct ieee80211_channel *channel = ar->hw->conf.chandef.chan; + struct cfg80211_chan_def *chandef = &ar->chandef; + struct ieee80211_channel *channel = chandef->chan; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (!ar->monitor_present) { - ath10k_warn("mac montor stop -- monitor is not present\n"); - return -EINVAL; - } - arg.vdev_id = vdev_id; arg.channel.freq = channel->center_freq; - arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; + arg.channel.band_center_freq1 = chandef->center_freq1; /* TODO setup this dynamically, what in case we don't have any vifs? */ - arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); + arg.channel.mode = chan_to_phymode(chandef); arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); @@ -555,81 +531,75 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { - ath10k_warn("Monitor vdev start failed: ret %d\n", ret); + ath10k_warn("failed to request monitor vdev %i start: %d\n", + vdev_id, ret); return ret; } ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn("Monitor vdev setup failed %d\n", ret); + ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n", + vdev_id, ret); return ret; } ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); if (ret) { - ath10k_warn("Monitor vdev up failed: %d\n", ret); + ath10k_warn("failed to put up monitor vdev %i: %d\n", + vdev_id, ret); goto vdev_stop; } ar->monitor_vdev_id = vdev_id; - ar->monitor_enabled = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n", + ar->monitor_vdev_id); return 0; vdev_stop: ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev stop failed: %d\n", ret); + ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n", + ar->monitor_vdev_id, ret); return ret; } -static int ath10k_monitor_stop(struct ath10k *ar) +static int ath10k_monitor_vdev_stop(struct ath10k *ar) { int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (!ar->monitor_present) { - ath10k_warn("mac montor stop -- monitor is not present\n"); - return -EINVAL; - } - - if (!ar->monitor_enabled) { - ath10k_warn("mac montor stop -- monitor is not enabled\n"); - return -EINVAL; - } - ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev down failed: %d\n", ret); + ath10k_warn("failed to put down monitor vdev %i: %d\n", + ar->monitor_vdev_id, ret); ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn("Monitor vdev stop failed: %d\n", ret); + ath10k_warn("failed to to request monitor vdev %i stop: %d\n", + ar->monitor_vdev_id, ret); ret = ath10k_vdev_setup_sync(ar); if (ret) - ath10k_warn("Monitor_down sync failed: %d\n", ret); + ath10k_warn("failed to synchronise monitor vdev %i: %d\n", + ar->monitor_vdev_id, ret); - ar->monitor_enabled = false; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", + ar->monitor_vdev_id); return ret; } -static int ath10k_monitor_create(struct ath10k *ar) +static int ath10k_monitor_vdev_create(struct ath10k *ar) { int bit, ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (ar->monitor_present) { - ath10k_warn("Monitor mode already enabled\n"); - return 0; - } - bit = ffs(ar->free_vdev_map); if (bit == 0) { - ath10k_warn("No free VDEV slots\n"); + ath10k_warn("failed to find free vdev id for monitor vdev\n"); return -ENOMEM; } @@ -640,14 +610,14 @@ static int ath10k_monitor_create(struct ath10k *ar) WMI_VDEV_TYPE_MONITOR, 0, ar->mac_addr); if (ret) { - ath10k_warn("WMI vdev monitor create failed: ret %d\n", ret); + ath10k_warn("failed to request monitor vdev %i creation: %d\n", + ar->monitor_vdev_id, ret); goto vdev_fail; } ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n", ar->monitor_vdev_id); - ar->monitor_present = true; return 0; vdev_fail: @@ -658,47 +628,123 @@ vdev_fail: return ret; } -static int ath10k_monitor_destroy(struct ath10k *ar) +static int ath10k_monitor_vdev_delete(struct ath10k *ar) { int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (!ar->monitor_present) - return 0; - ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id); if (ret) { - ath10k_warn("WMI vdev monitor delete failed: %d\n", ret); + ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n", + ar->monitor_vdev_id, ret); return ret; } ar->free_vdev_map |= 1 << (ar->monitor_vdev_id); - ar->monitor_present = false; ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", ar->monitor_vdev_id); return ret; } -static int ath10k_start_cac(struct ath10k *ar) +static int ath10k_monitor_start(struct ath10k *ar) { int ret; lockdep_assert_held(&ar->conf_mutex); - set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + if (!ath10k_monitor_is_enabled(ar)) { + ath10k_warn("trying to start monitor with no references\n"); + return 0; + } + + if (ar->monitor_started) { + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n"); + return 0; + } - ret = ath10k_monitor_create(ar); + ret = ath10k_monitor_vdev_create(ar); if (ret) { - clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ath10k_warn("failed to create monitor vdev: %d\n", ret); + return ret; + } + + ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); + if (ret) { + ath10k_warn("failed to start monitor vdev: %d\n", ret); + ath10k_monitor_vdev_delete(ar); return ret; } - ret = ath10k_monitor_start(ar, ar->monitor_vdev_id); + ar->monitor_started = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n"); + + return 0; +} + +static void ath10k_monitor_stop(struct ath10k *ar) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + if (ath10k_monitor_is_enabled(ar)) { + ath10k_dbg(ATH10K_DBG_MAC, + "mac monitor will be stopped later\n"); + return; + } + + if (!ar->monitor_started) { + ath10k_dbg(ATH10K_DBG_MAC, + "mac monitor probably failed to start earlier\n"); + return; + } + + ret = ath10k_monitor_vdev_stop(ar); + if (ret) + ath10k_warn("failed to stop monitor vdev: %d\n", ret); + + ret = ath10k_monitor_vdev_delete(ar); + if (ret) + ath10k_warn("failed to delete monitor vdev: %d\n", ret); + + ar->monitor_started = false; + ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n"); +} + +static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 vdev_param, rts_cts = 0; + + lockdep_assert_held(&ar->conf_mutex); + + vdev_param = ar->wmi.vdev_param->enable_rtscts; + + if (arvif->use_cts_prot || arvif->num_legacy_stations > 0) + rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET); + + if (arvif->num_legacy_stations > 0) + rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES, + WMI_RTSCTS_PROFILE); + + return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + rts_cts); +} + +static int ath10k_start_cac(struct ath10k *ar) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + + ret = ath10k_monitor_start(ar); if (ret) { + ath10k_warn("failed to start monitor (cac): %d\n", ret); clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); - ath10k_monitor_destroy(ar); return ret; } @@ -716,58 +762,26 @@ static int ath10k_stop_cac(struct ath10k *ar) if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) return 0; - ath10k_monitor_stop(ar); - ath10k_monitor_destroy(ar); clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ath10k_monitor_stop(ar); ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n"); return 0; } -static const char *ath10k_dfs_state(enum nl80211_dfs_state dfs_state) -{ - switch (dfs_state) { - case NL80211_DFS_USABLE: - return "USABLE"; - case NL80211_DFS_UNAVAILABLE: - return "UNAVAILABLE"; - case NL80211_DFS_AVAILABLE: - return "AVAILABLE"; - default: - WARN_ON(1); - return "bug"; - } -} - -static void ath10k_config_radar_detection(struct ath10k *ar) +static void ath10k_recalc_radar_detection(struct ath10k *ar) { - struct ieee80211_channel *chan = ar->hw->conf.chandef.chan; - bool radar = ar->hw->conf.radar_enabled; - bool chan_radar = !!(chan->flags & IEEE80211_CHAN_RADAR); - enum nl80211_dfs_state dfs_state = chan->dfs_state; int ret; lockdep_assert_held(&ar->conf_mutex); - ath10k_dbg(ATH10K_DBG_MAC, - "mac radar config update: chan %dMHz radar %d chan radar %d chan state %s\n", - chan->center_freq, radar, chan_radar, - ath10k_dfs_state(dfs_state)); - - /* - * It's safe to call it even if CAC is not started. - * This call here guarantees changing channel, etc. will stop CAC. - */ ath10k_stop_cac(ar); - if (!radar) - return; - - if (!chan_radar) + if (!ar->radar_enabled) return; - if (dfs_state != NL80211_DFS_USABLE) + if (ar->num_started_vdevs > 0) return; ret = ath10k_start_cac(ar); @@ -777,11 +791,106 @@ static void ath10k_config_radar_detection(struct ath10k *ar) * radiation is not allowed, make this channel DFS_UNAVAILABLE * by indicating that radar was detected. */ - ath10k_warn("failed to start CAC (%d)\n", ret); + ath10k_warn("failed to start CAC: %d\n", ret); ieee80211_radar_detected(ar->hw); } } +static int ath10k_vdev_start(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct cfg80211_chan_def *chandef = &ar->chandef; + struct wmi_vdev_start_request_arg arg = {}; + int ret = 0; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_setup_done); + + arg.vdev_id = arvif->vdev_id; + arg.dtim_period = arvif->dtim_period; + arg.bcn_intval = arvif->beacon_interval; + + arg.channel.freq = chandef->chan->center_freq; + arg.channel.band_center_freq1 = chandef->center_freq1; + arg.channel.mode = chan_to_phymode(chandef); + + arg.channel.min_power = 0; + arg.channel.max_power = chandef->chan->max_power * 2; + arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; + arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; + + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + arg.ssid = arvif->u.ap.ssid; + arg.ssid_len = arvif->u.ap.ssid_len; + arg.hidden_ssid = arvif->u.ap.hidden_ssid; + + /* For now allow DFS for AP mode */ + arg.channel.chan_radar = + !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); + } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { + arg.ssid = arvif->vif->bss_conf.ssid; + arg.ssid_len = arvif->vif->bss_conf.ssid_len; + } + + ath10k_dbg(ATH10K_DBG_MAC, + "mac vdev %d start center_freq %d phymode %s\n", + arg.vdev_id, arg.channel.freq, + ath10k_wmi_phymode_str(arg.channel.mode)); + + ret = ath10k_wmi_vdev_start(ar, &arg); + if (ret) { + ath10k_warn("failed to start WMI vdev %i: %d\n", + arg.vdev_id, ret); + return ret; + } + + ret = ath10k_vdev_setup_sync(ar); + if (ret) { + ath10k_warn("failed to synchronise setup for vdev %i: %d\n", + arg.vdev_id, ret); + return ret; + } + + ar->num_started_vdevs++; + ath10k_recalc_radar_detection(ar); + + return ret; +} + +static int ath10k_vdev_stop(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_setup_done); + + ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); + if (ret) { + ath10k_warn("failed to stop WMI vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + ret = ath10k_vdev_setup_sync(ar); + if (ret) { + ath10k_warn("failed to syncronise setup for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + WARN_ON(ar->num_started_vdevs == 0); + + if (ar->num_started_vdevs != 0) { + ar->num_started_vdevs--; + ath10k_recalc_radar_detection(ar); + } + + return ret; +} + static void ath10k_control_beaconing(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info) { @@ -791,6 +900,22 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (!info->enable_beacon) { ath10k_vdev_stop(arvif); + + arvif->is_started = false; + arvif->is_up = false; + + spin_lock_bh(&arvif->ar->data_lock); + if (arvif->beacon) { + dma_unmap_single(arvif->ar->dev, + ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); + dev_kfree_skb_any(arvif->beacon); + + arvif->beacon = NULL; + arvif->beacon_sent = false; + } + spin_unlock_bh(&arvif->ar->data_lock); + return; } @@ -800,12 +925,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (ret) return; - ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid); + arvif->aid = 0; + memcpy(arvif->bssid, info->bssid, ETH_ALEN); + + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, + arvif->bssid); if (ret) { - ath10k_warn("Failed to bring up VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to bring up vdev %d: %i\n", + arvif->vdev_id, ret); + ath10k_vdev_stop(arvif); return; } + + arvif->is_started = true; + arvif->is_up = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); } @@ -821,28 +955,28 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, if (!info->ibss_joined) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer); if (ret) - ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n", + ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n", self_peer, arvif->vdev_id, ret); - if (is_zero_ether_addr(arvif->u.ibss.bssid)) + if (is_zero_ether_addr(arvif->bssid)) return; ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, - arvif->u.ibss.bssid); + arvif->bssid); if (ret) { - ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n", - arvif->u.ibss.bssid, arvif->vdev_id, ret); + ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", + arvif->bssid, arvif->vdev_id, ret); return; } - memset(arvif->u.ibss.bssid, 0, ETH_ALEN); + memset(arvif->bssid, 0, ETH_ALEN); return; } ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer); if (ret) { - ath10k_warn("Failed to create IBSS self peer:%pM for VDEV:%d ret:%d\n", + ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n", self_peer, arvif->vdev_id, ret); return; } @@ -851,7 +985,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param, ATH10K_DEFAULT_ATIM); if (ret) - ath10k_warn("Failed to set IBSS ATIM for VDEV:%d ret:%d\n", + ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n", arvif->vdev_id, ret); } @@ -878,8 +1012,8 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, conf->dynamic_ps_timeout); if (ret) { - ath10k_warn("Failed to set inactivity time for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to set inactivity time for vdev %d: %i\n", + arvif->vdev_id, ret); return ret; } } else { @@ -891,8 +1025,8 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); if (ret) { - ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n", - psmode, arvif->vdev_id); + ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n", + psmode, arvif->vdev_id, ret); return ret; } @@ -1017,7 +1151,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, struct wmi_peer_assoc_complete_arg *arg) { const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - int smps; int i, n; lockdep_assert_held(&ar->conf_mutex); @@ -1063,17 +1196,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_flags |= WMI_PEER_STBC; } - smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; - smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; - - if (smps == WLAN_HT_CAP_SM_PS_STATIC) { - arg->peer_flags |= WMI_PEER_SPATIAL_MUX; - arg->peer_flags |= WMI_PEER_STATIC_MIMOPS; - } else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) { - arg->peer_flags |= WMI_PEER_SPATIAL_MUX; - arg->peer_flags |= WMI_PEER_DYN_MIMOPS; - } - if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2]) arg->peer_rate_caps |= WMI_RC_TS_FLAG; else if (ht_cap->mcs.rx_mask[1]) @@ -1083,8 +1205,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8)) arg->peer_ht_rates.rates[n++] = i; - arg->peer_ht_rates.num_rates = n; - arg->peer_num_spatial_streams = max((n+7) / 8, 1); + /* + * This is a workaround for HT-enabled STAs which break the spec + * and have no HT capabilities RX mask (no HT RX MCS map). + * + * As per spec, in section 20.3.5 Modulation and coding scheme (MCS), + * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs. + * + * Firmware asserts if such situation occurs. + */ + if (n == 0) { + arg->peer_ht_rates.num_rates = 8; + for (i = 0; i < arg->peer_ht_rates.num_rates; i++) + arg->peer_ht_rates.rates[i] = i; + } else { + arg->peer_ht_rates.num_rates = n; + arg->peer_num_spatial_streams = sta->rx_nss; + } ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", arg->addr, @@ -1092,27 +1229,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_num_spatial_streams); } -static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, - struct ath10k_vif *arvif, - struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, - struct wmi_peer_assoc_complete_arg *arg) +static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, + struct ath10k_vif *arvif, + struct ieee80211_sta *sta) { u32 uapsd = 0; u32 max_sp = 0; + int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (sta->wme) - arg->peer_flags |= WMI_PEER_QOS; - if (sta->wme && sta->uapsd_queues) { ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", sta->uapsd_queues, sta->max_sp); - arg->peer_flags |= WMI_PEER_APSD; - arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; - if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; @@ -1130,35 +1260,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) max_sp = sta->max_sp; - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_UAPSD, - uapsd); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + WMI_AP_PS_PEER_PARAM_UAPSD, + uapsd); + if (ret) { + ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_MAX_SP, - max_sp); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + WMI_AP_PS_PEER_PARAM_MAX_SP, + max_sp); + if (ret) { + ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } /* TODO setup this based on STA listen interval and beacon interval. Currently we don't know sta->listen_interval - mac80211 patch required. Currently use 10 seconds */ - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, - 10); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, + WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10); + if (ret) { + ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } } -} -static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar, - struct ath10k_vif *arvif, - struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, - struct wmi_peer_assoc_complete_arg *arg) -{ - if (bss_conf->qos) - arg->peer_flags |= WMI_PEER_QOS; + return 0; } static void ath10k_peer_assoc_h_vht(struct ath10k *ar, @@ -1211,10 +1346,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, { switch (arvif->vdev_type) { case WMI_VDEV_TYPE_AP: - ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg); + if (sta->wme) + arg->peer_flags |= WMI_PEER_QOS; + + if (sta->wme && sta->uapsd_queues) { + arg->peer_flags |= WMI_PEER_APSD; + arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; + } break; case WMI_VDEV_TYPE_STA: - ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg); + if (bss_conf->qos) + arg->peer_flags |= WMI_PEER_QOS; break; default: break; @@ -1293,6 +1435,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar, return 0; } +static const u32 ath10k_smps_map[] = { + [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC, + [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC, + [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE, + [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, +}; + +static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, + const u8 *addr, + const struct ieee80211_sta_ht_cap *ht_cap) +{ + int smps; + + if (!ht_cap->ht_supported) + return 0; + + smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; + smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; + + if (smps >= ARRAY_SIZE(ath10k_smps_map)) + return -EINVAL; + + return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr, + WMI_PEER_SMPS_STATE, + ath10k_smps_map[smps]); +} + /* can be called only in mac80211 callbacks due to `key_count` usage */ static void ath10k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1300,6 +1469,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct ieee80211_sta_ht_cap ht_cap; struct wmi_peer_assoc_complete_arg peer_arg; struct ieee80211_sta *ap_sta; int ret; @@ -1310,17 +1480,21 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); if (!ap_sta) { - ath10k_warn("Failed to find station entry for %pM\n", - bss_conf->bssid); + ath10k_warn("failed to find station entry for bss %pM vdev %i\n", + bss_conf->bssid, arvif->vdev_id); rcu_read_unlock(); return; } + /* ap_sta must be accessed only within rcu section which must be left + * before calling ath10k_setup_peer_smps() which might sleep. */ + ht_cap = ap_sta->ht_cap; + ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, bss_conf, &peer_arg); if (ret) { - ath10k_warn("Peer assoc prepare failed for %pM\n: %d", - bss_conf->bssid, ret); + ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n", + bss_conf->bssid, arvif->vdev_id, ret); rcu_read_unlock(); return; } @@ -1329,8 +1503,15 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("Peer assoc failed for %pM\n: %d", - bss_conf->bssid, ret); + ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n", + bss_conf->bssid, arvif->vdev_id, ret); + return; + } + + ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap); + if (ret) { + ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n", + arvif->vdev_id, ret); return; } @@ -1338,11 +1519,17 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); - ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid, - bss_conf->bssid); - if (ret) - ath10k_warn("VDEV: %d up failed: ret %d\n", + arvif->aid = bss_conf->aid; + memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN); + + ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); + if (ret) { + ath10k_warn("failed to set vdev %d up: %d\n", arvif->vdev_id, ret); + return; + } + + arvif->is_up = true; } /* @@ -1382,10 +1569,13 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); arvif->def_wep_key_idx = 0; + + arvif->is_started = false; + arvif->is_up = false; } static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta, bool reassoc) { struct wmi_peer_assoc_complete_arg peer_arg; int ret = 0; @@ -1394,21 +1584,47 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg); if (ret) { - ath10k_warn("WMI peer assoc prepare failed for %pM\n", - sta->addr); + ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n", + sta->addr, arvif->vdev_id, ret); return ret; } + peer_arg.peer_reassoc = reassoc; ret = ath10k_wmi_peer_assoc(ar, &peer_arg); if (ret) { - ath10k_warn("Peer assoc failed for STA %pM\n: %d", - sta->addr, ret); + ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n", + sta->addr, arvif->vdev_id, ret); return ret; } + ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap); + if (ret) { + ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n", + arvif->vdev_id, ret); + return ret; + } + + if (!sta->wme) { + arvif->num_legacy_stations++; + ret = ath10k_recalc_rtscts_prot(arvif); + if (ret) { + ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + ret = ath10k_install_peer_wep_keys(arvif, sta->addr); if (ret) { - ath10k_warn("could not install peer wep keys (%d)\n", ret); + ath10k_warn("failed to install peer wep keys for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); + if (ret) { + ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n", + sta->addr, arvif->vdev_id, ret); return ret; } @@ -1422,9 +1638,20 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); + if (!sta->wme) { + arvif->num_legacy_stations--; + ret = ath10k_recalc_rtscts_prot(arvif); + if (ret) { + ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + ret = ath10k_clear_peer_keys(arvif, sta->addr); if (ret) { - ath10k_warn("could not clear all peer wep keys (%d)\n", ret); + ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n", + arvif->vdev_id, ret); return ret; } @@ -1531,29 +1758,55 @@ static int ath10k_update_channel_list(struct ath10k *ar) return ret; } +static enum wmi_dfs_region +ath10k_mac_get_dfs_region(enum nl80211_dfs_regions dfs_region) +{ + switch (dfs_region) { + case NL80211_DFS_UNSET: + return WMI_UNINIT_DFS_DOMAIN; + case NL80211_DFS_FCC: + return WMI_FCC_DFS_DOMAIN; + case NL80211_DFS_ETSI: + return WMI_ETSI_DFS_DOMAIN; + case NL80211_DFS_JP: + return WMI_MKK4_DFS_DOMAIN; + } + return WMI_UNINIT_DFS_DOMAIN; +} + static void ath10k_regd_update(struct ath10k *ar) { struct reg_dmn_pair_mapping *regpair; int ret; + enum wmi_dfs_region wmi_dfs_reg; + enum nl80211_dfs_regions nl_dfs_reg; lockdep_assert_held(&ar->conf_mutex); ret = ath10k_update_channel_list(ar); if (ret) - ath10k_warn("could not update channel list (%d)\n", ret); + ath10k_warn("failed to update channel list: %d\n", ret); regpair = ar->ath_common.regulatory.regpair; + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { + nl_dfs_reg = ar->dfs_detector->region; + wmi_dfs_reg = ath10k_mac_get_dfs_region(nl_dfs_reg); + } else { + wmi_dfs_reg = WMI_UNINIT_DFS_DOMAIN; + } + /* Target allows setting up per-band regdomain but ath_common provides * a combined one only */ ret = ath10k_wmi_pdev_set_regdomain(ar, - regpair->regDmnEnum, - regpair->regDmnEnum, /* 2ghz */ - regpair->regDmnEnum, /* 5ghz */ + regpair->reg_domain, + regpair->reg_domain, /* 2ghz */ + regpair->reg_domain, /* 5ghz */ regpair->reg_2ghz_ctl, - regpair->reg_5ghz_ctl); + regpair->reg_5ghz_ctl, + wmi_dfs_reg); if (ret) - ath10k_warn("could not set pdev regdomain (%d)\n", ret); + ath10k_warn("failed to set pdev regdomain: %d\n", ret); } static void ath10k_reg_notifier(struct wiphy *wiphy, @@ -1571,7 +1824,7 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, request->dfs_region); if (!result) - ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n", + ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n", request->dfs_region); } @@ -1605,10 +1858,10 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, if (info->control.vif) return ath10k_vif_to_arvif(info->control.vif)->vdev_id; - if (ar->monitor_enabled) + if (ar->monitor_started) return ar->monitor_vdev_id; - ath10k_warn("could not resolve vdev id\n"); + ath10k_warn("failed to resolve vdev id\n"); return 0; } @@ -1638,8 +1891,13 @@ static void ath10k_tx_wep_key_work(struct work_struct *work) wep_key_work); int ret, keyidx = arvif->def_wep_key_newidx; + mutex_lock(&arvif->ar->conf_mutex); + + if (arvif->ar->state != ATH10K_STATE_ON) + goto unlock; + if (arvif->def_wep_key_idx == keyidx) - return; + goto unlock; ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", arvif->vdev_id, keyidx); @@ -1649,11 +1907,16 @@ static void ath10k_tx_wep_key_work(struct work_struct *work) arvif->ar->wmi.vdev_param->def_keyid, keyidx); if (ret) { - ath10k_warn("could not update wep keyidx (%d)\n", ret); - return; + ath10k_warn("failed to update wep key index for vdev %d: %d\n", + arvif->vdev_id, + ret); + goto unlock; } arvif->def_wep_key_idx = keyidx; + +unlock: + mutex_unlock(&arvif->ar->conf_mutex); } static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) @@ -1725,7 +1988,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) ar->fw_features)) { if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >= ATH10K_MAX_NUM_MGMT_PENDING) { - ath10k_warn("wmi mgmt_tx queue limit reached\n"); + ath10k_warn("reached WMI management tranmist queue limit\n"); ret = -EBUSY; goto exit; } @@ -1749,7 +2012,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) exit: if (ret) { - ath10k_warn("tx failed (%d). dropping packet.\n", ret); + ath10k_warn("failed to transmit packet, dropping: %d\n", ret); ieee80211_free_txskb(ar->hw, skb); } } @@ -1810,7 +2073,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) if (!peer) { ret = ath10k_peer_create(ar, vdev_id, peer_addr); if (ret) - ath10k_warn("peer %pM on vdev %d not created (%d)\n", + ath10k_warn("failed to create peer %pM on vdev %d: %d\n", peer_addr, vdev_id, ret); } @@ -1830,7 +2093,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) if (!peer) { ret = ath10k_peer_delete(ar, vdev_id, peer_addr); if (ret) - ath10k_warn("peer %pM on vdev %d not deleted (%d)\n", + ath10k_warn("failed to delete peer %pM on vdev %d: %d\n", peer_addr, vdev_id, ret); } @@ -1864,7 +2127,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) ret = ath10k_wmi_mgmt_tx(ar, skb); if (ret) { - ath10k_warn("wmi mgmt_tx failed (%d)\n", ret); + ath10k_warn("failed to transmit management frame via WMI: %d\n", + ret); ieee80211_free_txskb(ar->hw, skb); } } @@ -1889,7 +2153,7 @@ void ath10k_reset_scan(unsigned long ptr) return; } - ath10k_warn("scan timeout. resetting. fw issue?\n"); + ath10k_warn("scan timed out, firmware problem?\n"); if (ar->scan.is_roc) ieee80211_remain_on_channel_expired(ar->hw); @@ -1925,7 +2189,7 @@ static int ath10k_abort_scan(struct ath10k *ar) ret = ath10k_wmi_stop_scan(ar, &arg); if (ret) { - ath10k_warn("could not submit wmi stop scan (%d)\n", ret); + ath10k_warn("failed to stop wmi scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.in_progress = false; ath10k_offchan_tx_purge(ar); @@ -1945,7 +2209,7 @@ static int ath10k_abort_scan(struct ath10k *ar) spin_lock_bh(&ar->data_lock); if (ar->scan.in_progress) { - ath10k_warn("could not stop scan. its still in progress\n"); + ath10k_warn("failed to stop scan, it's still in progress\n"); ar->scan.in_progress = false; ath10k_offchan_tx_purge(ar); ret = -ETIMEDOUT; @@ -2033,97 +2297,222 @@ static void ath10k_tx(struct ieee80211_hw *hw, ath10k_tx_htt(ar, skb); } -/* - * Initialize various parameters with default vaules. - */ +/* Must not be called with conf_mutex held as workers can use that also. */ +static void ath10k_drain_tx(struct ath10k *ar) +{ + /* make sure rcu-protected mac80211 tx path itself is drained */ + synchronize_net(); + + ath10k_offchan_tx_purge(ar); + ath10k_mgmt_over_wmi_tx_purge(ar); + + cancel_work_sync(&ar->offchan_tx_work); + cancel_work_sync(&ar->wmi_mgmt_tx_work); +} + void ath10k_halt(struct ath10k *ar) { + struct ath10k_vif *arvif; + lockdep_assert_held(&ar->conf_mutex); - ath10k_stop_cac(ar); + if (ath10k_monitor_is_enabled(ar)) { + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); + ar->promisc = false; + ar->monitor = false; + ath10k_monitor_stop(ar); + } + del_timer_sync(&ar->scan.timeout); - ath10k_offchan_tx_purge(ar); - ath10k_mgmt_over_wmi_tx_purge(ar); + ath10k_reset_scan((unsigned long)ar); ath10k_peer_cleanup_all(ar); ath10k_core_stop(ar); ath10k_hif_power_down(ar); spin_lock_bh(&ar->data_lock); - if (ar->scan.in_progress) { - del_timer(&ar->scan.timeout); - ar->scan.in_progress = false; - ieee80211_scan_completed(ar->hw, true); + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->beacon) + continue; + + dma_unmap_single(arvif->ar->dev, + ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); + dev_kfree_skb_any(arvif->beacon); + arvif->beacon = NULL; } spin_unlock_bh(&ar->data_lock); } +static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct ath10k *ar = hw->priv; + + mutex_lock(&ar->conf_mutex); + + if (ar->cfg_tx_chainmask) { + *tx_ant = ar->cfg_tx_chainmask; + *rx_ant = ar->cfg_rx_chainmask; + } else { + *tx_ant = ar->supp_tx_chainmask; + *rx_ant = ar->supp_rx_chainmask; + } + + mutex_unlock(&ar->conf_mutex); + + return 0; +} + +static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) +{ + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ar->cfg_tx_chainmask = tx_ant; + ar->cfg_rx_chainmask = rx_ant; + + if ((ar->state != ATH10K_STATE_ON) && + (ar->state != ATH10K_STATE_RESTARTED)) + return 0; + + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask, + tx_ant); + if (ret) { + ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n", + ret, tx_ant); + return ret; + } + + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask, + rx_ant); + if (ret) { + ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n", + ret, rx_ant); + return ret; + } + + return 0; +} + +static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct ath10k *ar = hw->priv; + int ret; + + mutex_lock(&ar->conf_mutex); + ret = __ath10k_set_antenna(ar, tx_ant, rx_ant); + mutex_unlock(&ar->conf_mutex); + return ret; +} + static int ath10k_start(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; int ret = 0; + /* + * This makes sense only when restarting hw. It is harmless to call + * uncoditionally. This is necessary to make sure no HTT/WMI tx + * commands will be submitted while restarting. + */ + ath10k_drain_tx(ar); + mutex_lock(&ar->conf_mutex); - if (ar->state != ATH10K_STATE_OFF && - ar->state != ATH10K_STATE_RESTARTING) { + switch (ar->state) { + case ATH10K_STATE_OFF: + ar->state = ATH10K_STATE_ON; + break; + case ATH10K_STATE_RESTARTING: + ath10k_halt(ar); + ar->state = ATH10K_STATE_RESTARTED; + break; + case ATH10K_STATE_ON: + case ATH10K_STATE_RESTARTED: + case ATH10K_STATE_WEDGED: + WARN_ON(1); ret = -EINVAL; - goto exit; + goto err; } ret = ath10k_hif_power_up(ar); if (ret) { - ath10k_err("could not init hif (%d)\n", ret); - ar->state = ATH10K_STATE_OFF; - goto exit; + ath10k_err("Could not init hif: %d\n", ret); + goto err_off; } ret = ath10k_core_start(ar); if (ret) { - ath10k_err("could not init core (%d)\n", ret); - ath10k_hif_power_down(ar); - ar->state = ATH10K_STATE_OFF; - goto exit; + ath10k_err("Could not init core: %d\n", ret); + goto err_power_down; } - if (ar->state == ATH10K_STATE_OFF) - ar->state = ATH10K_STATE_ON; - else if (ar->state == ATH10K_STATE_RESTARTING) - ar->state = ATH10K_STATE_RESTARTED; - ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1); - if (ret) - ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", - ret); + if (ret) { + ath10k_warn("failed to enable PMF QOS: %d\n", ret); + goto err_core_stop; + } ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1); - if (ret) - ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", + if (ret) { + ath10k_warn("failed to enable dynamic BW: %d\n", ret); + goto err_core_stop; + } + + if (ar->cfg_tx_chainmask) + __ath10k_set_antenna(ar, ar->cfg_tx_chainmask, + ar->cfg_rx_chainmask); + + /* + * By default FW set ARP frames ac to voice (6). In that case ARP + * exchange is not working properly for UAPSD enabled AP. ARP requests + * which arrives with access category 0 are processed by network stack + * and send back with access category 0, but FW changes access category + * to 6. Set ARP frames access category to best effort (0) solves + * this problem. + */ + + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->arp_ac_override, 0); + if (ret) { + ath10k_warn("failed to set arp ac override parameter: %d\n", ret); + goto err_core_stop; + } + ar->num_started_vdevs = 0; ath10k_regd_update(ar); -exit: mutex_unlock(&ar->conf_mutex); return 0; + +err_core_stop: + ath10k_core_stop(ar); + +err_power_down: + ath10k_hif_power_down(ar); + +err_off: + ar->state = ATH10K_STATE_OFF; + +err: + mutex_unlock(&ar->conf_mutex); + return ret; } static void ath10k_stop(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; + ath10k_drain_tx(ar); + mutex_lock(&ar->conf_mutex); - if (ar->state == ATH10K_STATE_ON || - ar->state == ATH10K_STATE_RESTARTED || - ar->state == ATH10K_STATE_WEDGED) + if (ar->state != ATH10K_STATE_OFF) { ath10k_halt(ar); - - ar->state = ATH10K_STATE_OFF; + ar->state = ATH10K_STATE_OFF; + } mutex_unlock(&ar->conf_mutex); - ath10k_mgmt_over_wmi_tx_purge(ar); - - cancel_work_sync(&ar->offchan_tx_work); - cancel_work_sync(&ar->wmi_mgmt_tx_work); cancel_work_sync(&ar->restart_work); } @@ -2137,7 +2526,7 @@ static int ath10k_config_ps(struct ath10k *ar) list_for_each_entry(arvif, &ar->arvifs, list) { ret = ath10k_mac_vif_setup_ps(arvif); if (ret) { - ath10k_warn("could not setup powersave (%d)\n", ret); + ath10k_warn("failed to setup powersave: %d\n", ret); break; } } @@ -2145,6 +2534,95 @@ static int ath10k_config_ps(struct ath10k *ar) return ret; } +static const char *chandef_get_width(enum nl80211_chan_width width) +{ + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + return "20 (noht)"; + case NL80211_CHAN_WIDTH_20: + return "20"; + case NL80211_CHAN_WIDTH_40: + return "40"; + case NL80211_CHAN_WIDTH_80: + return "80"; + case NL80211_CHAN_WIDTH_80P80: + return "80+80"; + case NL80211_CHAN_WIDTH_160: + return "160"; + case NL80211_CHAN_WIDTH_5: + return "5"; + case NL80211_CHAN_WIDTH_10: + return "10"; + } + return "?"; +} + +static void ath10k_config_chan(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ath10k_dbg(ATH10K_DBG_MAC, + "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n", + ar->chandef.chan->center_freq, + ar->chandef.center_freq1, + ar->chandef.center_freq2, + chandef_get_width(ar->chandef.width)); + + /* First stop monitor interface. Some FW versions crash if there's a + * lone monitor interface. */ + if (ar->monitor_started) + ath10k_monitor_vdev_stop(ar); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + continue; + + ret = ath10k_vdev_stop(arvif); + if (ret) { + ath10k_warn("failed to stop vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } + } + + /* all vdevs are now stopped - now attempt to restart them */ + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + continue; + + ret = ath10k_vdev_start(arvif); + if (ret) { + ath10k_warn("failed to start vdev %d: %d\n", + arvif->vdev_id, ret); + continue; + } + + if (!arvif->is_up) + continue; + + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, + arvif->bssid); + if (ret) { + ath10k_warn("failed to bring vdev up %d: %d\n", + arvif->vdev_id, ret); + continue; + } + } + + if (ath10k_monitor_is_enabled(ar)) + ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); +} + static int ath10k_config(struct ieee80211_hw *hw, u32 changed) { struct ath10k *ar = hw->priv; @@ -2156,15 +2634,22 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ath10k_dbg(ATH10K_DBG_MAC, - "mac config channel %d mhz flags 0x%x\n", + "mac config channel %dMHz flags 0x%x radar %d\n", conf->chandef.chan->center_freq, - conf->chandef.chan->flags); + conf->chandef.chan->flags, + conf->radar_enabled); spin_lock_bh(&ar->data_lock); ar->rx_channel = conf->chandef.chan; spin_unlock_bh(&ar->data_lock); - ath10k_config_radar_detection(ar); + ar->radar_enabled = conf->radar_enabled; + ath10k_recalc_radar_detection(ar); + + if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) { + ar->chandef = conf->chandef; + ath10k_config_chan(ar); + } } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -2175,14 +2660,14 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ret = ath10k_wmi_pdev_set_param(ar, param, hw->conf.power_level * 2); if (ret) - ath10k_warn("mac failed to set 2g txpower %d (%d)\n", + ath10k_warn("failed to set 2g txpower %d: %d\n", hw->conf.power_level, ret); param = ar->wmi.pdev_param->txpower_limit5g; ret = ath10k_wmi_pdev_set_param(ar, param, hw->conf.power_level * 2); if (ret) - ath10k_warn("mac failed to set 5g txpower %d (%d)\n", + ath10k_warn("failed to set 5g txpower %d: %d\n", hw->conf.power_level, ret); } @@ -2190,10 +2675,19 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ath10k_config_ps(ar); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - if (conf->flags & IEEE80211_CONF_MONITOR) - ret = ath10k_monitor_create(ar); - else - ret = ath10k_monitor_destroy(ar); + if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) { + ar->monitor = true; + ret = ath10k_monitor_start(ar); + if (ret) { + ath10k_warn("failed to start monitor (config): %d\n", + ret); + ar->monitor = false; + } + } else if (!(conf->flags & IEEE80211_CONF_MONITOR) && + ar->monitor) { + ar->monitor = false; + ath10k_monitor_stop(ar); + } } mutex_unlock(&ar->conf_mutex); @@ -2214,7 +2708,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); enum wmi_sta_powersave_param param; int ret = 0; - u32 value, param_id; + u32 value; int bit; u32 vdev_param; @@ -2228,12 +2722,6 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); INIT_LIST_HEAD(&arvif->list); - if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) { - ath10k_warn("Only one monitor interface allowed\n"); - ret = -EBUSY; - goto err; - } - bit = ffs(ar->free_vdev_map); if (bit == 0) { ret = -EBUSY; @@ -2276,7 +2764,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, vif->addr); if (ret) { - ath10k_warn("WMI vdev create failed: ret %d\n", ret); + ath10k_warn("failed to create WMI vdev %i: %d\n", + arvif->vdev_id, ret); goto err; } @@ -2287,7 +2776,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, arvif->def_wep_key_idx); if (ret) { - ath10k_warn("Failed to set default keyid: %d\n", ret); + ath10k_warn("failed to set vdev %i default key id: %d\n", + arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2296,23 +2786,25 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ATH10K_HW_TXRX_NATIVE_WIFI); /* 10.X firmware does not support this VDEV parameter. Do not warn */ if (ret && ret != -EOPNOTSUPP) { - ath10k_warn("Failed to set TX encap: %d\n", ret); + ath10k_warn("failed to set vdev %i TX encapsulation: %d\n", + arvif->vdev_id, ret); goto err_vdev_delete; } if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); if (ret) { - ath10k_warn("Failed to create peer for AP: %d\n", ret); + ath10k_warn("failed to create vdev %i peer for AP: %d\n", + arvif->vdev_id, ret); goto err_vdev_delete; } - param_id = ar->wmi.pdev_param->sta_kickout_th; - - /* Disable STA KICKOUT functionality in FW */ - ret = ath10k_wmi_pdev_set_param(ar, param_id, 0); - if (ret) - ath10k_warn("Failed to disable STA KICKOUT\n"); + ret = ath10k_mac_set_kickout(arvif); + if (ret) { + ath10k_warn("failed to set vdev %i kickout parameters: %d\n", + arvif->vdev_id, ret); + goto err_peer_delete; + } } if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { @@ -2321,7 +2813,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set RX wake policy: %d\n", ret); + ath10k_warn("failed to set vdev %i RX wake policy: %d\n", + arvif->vdev_id, ret); goto err_peer_delete; } @@ -2330,7 +2823,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set TX wake thresh: %d\n", ret); + ath10k_warn("failed to set vdev %i TX wake thresh: %d\n", + arvif->vdev_id, ret); goto err_peer_delete; } @@ -2339,28 +2833,26 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); if (ret) { - ath10k_warn("Failed to set PSPOLL count: %d\n", ret); + ath10k_warn("failed to set vdev %i PSPOLL count: %d\n", + arvif->vdev_id, ret); goto err_peer_delete; } } ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); if (ret) { - ath10k_warn("failed to set rts threshold for vdev %d (%d)\n", + ath10k_warn("failed to set rts threshold for vdev %d: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold); if (ret) { - ath10k_warn("failed to set frag threshold for vdev %d (%d)\n", + ath10k_warn("failed to set frag threshold for vdev %d: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - ar->monitor_present = true; - mutex_unlock(&ar->conf_mutex); return 0; @@ -2392,6 +2884,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, spin_lock_bh(&ar->data_lock); if (arvif->beacon) { + dma_unmap_single(arvif->ar->dev, + ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); dev_kfree_skb_any(arvif->beacon); arvif->beacon = NULL; } @@ -2403,20 +2898,19 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); if (ret) - ath10k_warn("Failed to remove peer for AP: %d\n", ret); + ath10k_warn("failed to remove peer for AP vdev %i: %d\n", + arvif->vdev_id, ret); kfree(arvif->u.ap.noa_data); } - ath10k_dbg(ATH10K_DBG_MAC, "mac vdev delete %d (remove interface)\n", + ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", arvif->vdev_id); ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id); if (ret) - ath10k_warn("WMI vdev delete failed: %d\n", ret); - - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - ar->monitor_present = false; + ath10k_warn("failed to delete WMI vdev %i: %d\n", + arvif->vdev_id, ret); ath10k_peer_cleanup(ar, arvif->vdev_id); @@ -2450,28 +2944,17 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, *total_flags &= SUPPORTED_FILTERS; ar->filter_flags = *total_flags; - /* Monitor must not be started if it wasn't created first. - * Promiscuous mode may be started on a non-monitor interface - in - * such case the monitor vdev is not created so starting the - * monitor makes no sense. Since ath10k uses no special RX filters - * (only BSS filter in STA mode) there's no need for any special - * action here. */ - if ((ar->filter_flags & FIF_PROMISC_IN_BSS) && - !ar->monitor_enabled && ar->monitor_present) { - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d start\n", - ar->monitor_vdev_id); - - ret = ath10k_monitor_start(ar, ar->monitor_vdev_id); - if (ret) - ath10k_warn("Unable to start monitor mode\n"); - } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && - ar->monitor_enabled && ar->monitor_present) { - ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d stop\n", - ar->monitor_vdev_id); - - ret = ath10k_monitor_stop(ar); - if (ret) - ath10k_warn("Unable to stop monitor mode\n"); + if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) { + ar->promisc = true; + ret = ath10k_monitor_start(ar); + if (ret) { + ath10k_warn("failed to start monitor (promisc): %d\n", + ret); + ar->promisc = false; + } + } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) { + ar->promisc = false; + ath10k_monitor_stop(ar); } mutex_unlock(&ar->conf_mutex); @@ -2502,8 +2985,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, arvif->beacon_interval); if (ret) - ath10k_warn("Failed to set beacon interval for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to set beacon interval for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_BEACON) { @@ -2515,8 +2998,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_pdev_set_param(ar, pdev_param, WMI_BEACON_STAGGERED_MODE); if (ret) - ath10k_warn("Failed to set beacon mode for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to set beacon mode for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_BEACON_INFO) { @@ -2530,8 +3013,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, arvif->dtim_period); if (ret) - ath10k_warn("Failed to set dtim period for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to set dtim period for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_SSID && @@ -2542,7 +3025,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->u.ap.hidden_ssid = info->hidden_ssid; } - if (changed & BSS_CHANGED_BSSID) { + /* + * Firmware manages AP self-peer internally so make sure to not create + * it in driver. Otherwise AP self-peer deletion may timeout later. + */ + if (changed & BSS_CHANGED_BSSID && + vif->type != NL80211_IFTYPE_AP) { if (!is_zero_ether_addr(info->bssid)) { ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d create peer %pM\n", @@ -2551,7 +3039,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, info->bssid); if (ret) - ath10k_warn("Failed to add peer %pM for vdev %d when changin bssid: %i\n", + ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n", info->bssid, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) { @@ -2559,15 +3047,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * this is never erased as we it for crypto key * clearing; this is FW requirement */ - memcpy(arvif->u.sta.bssid, info->bssid, - ETH_ALEN); + memcpy(arvif->bssid, info->bssid, ETH_ALEN); ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d start %pM\n", arvif->vdev_id, info->bssid); - /* FIXME: check return value */ ret = ath10k_vdev_start(arvif); + if (ret) { + ath10k_warn("failed to start vdev %i: %d\n", + arvif->vdev_id, ret); + goto exit; + } + + arvif->is_started = true; } /* @@ -2576,7 +3069,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * IBSS in order to remove BSSID peer. */ if (vif->type == NL80211_IFTYPE_ADHOC) - memcpy(arvif->u.ibss.bssid, info->bssid, + memcpy(arvif->bssid, info->bssid, ETH_ALEN); } } @@ -2585,21 +3078,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_control_beaconing(arvif, info); if (changed & BSS_CHANGED_ERP_CTS_PROT) { - u32 cts_prot; - if (info->use_cts_prot) - cts_prot = 1; - else - cts_prot = 0; - + arvif->use_cts_prot = info->use_cts_prot; ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", - arvif->vdev_id, cts_prot); + arvif->vdev_id, info->use_cts_prot); - vdev_param = ar->wmi.vdev_param->enable_rtscts; - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, - cts_prot); + ret = ath10k_recalc_rtscts_prot(arvif); if (ret) - ath10k_warn("Failed to set CTS prot for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -2617,8 +3103,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, slottime); if (ret) - ath10k_warn("Failed to set erp slot for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to set erp slot for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -2636,8 +3122,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, preamble); if (ret) - ath10k_warn("Failed to set preamble for VDEV: %d\n", - arvif->vdev_id); + ath10k_warn("failed to set preamble for vdev %d: %i\n", + arvif->vdev_id, ret); } if (changed & BSS_CHANGED_ASSOC) { @@ -2645,6 +3131,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_bss_assoc(hw, vif, info); } +exit: mutex_unlock(&ar->conf_mutex); } @@ -2706,7 +3193,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, ret = ath10k_start_scan(ar, &arg); if (ret) { - ath10k_warn("could not start hw scan (%d)\n", ret); + ath10k_warn("failed to start hw scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.in_progress = false; spin_unlock_bh(&ar->data_lock); @@ -2726,8 +3213,7 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ret = ath10k_abort_scan(ar); if (ret) { - ath10k_warn("couldn't abort scan (%d). forcefully sending scan completion to mac80211\n", - ret); + ath10k_warn("failed to abort scan: %d\n", ret); ieee80211_scan_completed(hw, 1 /* aborted */); } mutex_unlock(&ar->conf_mutex); @@ -2767,8 +3253,8 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, key->keyidx); if (ret) - ath10k_warn("failed to set group key as default key: %d\n", - ret); + ath10k_warn("failed to set vdev %i group key as default key: %d\n", + arvif->vdev_id, ret); } static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -2805,7 +3291,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!peer) { if (cmd == SET_KEY) { - ath10k_warn("cannot install key for non-existent peer %pM\n", + ath10k_warn("failed to install key for non-existent peer %pM\n", peer_addr); ret = -EOPNOTSUPP; goto exit; @@ -2828,7 +3314,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr); if (ret) { - ath10k_warn("ath10k_install_key failed (%d)\n", ret); + ath10k_warn("failed to install key for vdev %i peer %pM: %d\n", + arvif->vdev_id, peer_addr, ret); goto exit; } @@ -2842,7 +3329,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, peer->keys[key->keyidx] = NULL; else if (peer == NULL) /* impossible unless FW goes crazy */ - ath10k_warn("peer %pM disappeared!\n", peer_addr); + ath10k_warn("Peer %pM disappeared!\n", peer_addr); spin_unlock_bh(&ar->data_lock); exit: @@ -2850,6 +3337,79 @@ exit: return ret; } +static void ath10k_sta_rc_update_wk(struct work_struct *wk) +{ + struct ath10k *ar; + struct ath10k_vif *arvif; + struct ath10k_sta *arsta; + struct ieee80211_sta *sta; + u32 changed, bw, nss, smps; + int err; + + arsta = container_of(wk, struct ath10k_sta, update_wk); + sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); + arvif = arsta->arvif; + ar = arvif->ar; + + spin_lock_bh(&ar->data_lock); + + changed = arsta->changed; + arsta->changed = 0; + + bw = arsta->bw; + nss = arsta->nss; + smps = arsta->smps; + + spin_unlock_bh(&ar->data_lock); + + mutex_lock(&ar->conf_mutex); + + if (changed & IEEE80211_RC_BW_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", + sta->addr, bw); + + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_CHAN_WIDTH, bw); + if (err) + ath10k_warn("failed to update STA %pM peer bw %d: %d\n", + sta->addr, bw, err); + } + + if (changed & IEEE80211_RC_NSS_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", + sta->addr, nss); + + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_NSS, nss); + if (err) + ath10k_warn("failed to update STA %pM nss %d: %d\n", + sta->addr, nss, err); + } + + if (changed & IEEE80211_RC_SMPS_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", + sta->addr, smps); + + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_SMPS_STATE, smps); + if (err) + ath10k_warn("failed to update STA %pM smps %d: %d\n", + sta->addr, smps, err); + } + + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", + sta->addr); + + err = ath10k_station_assoc(ar, arvif, sta, true); + if (err) + ath10k_warn("failed to reassociate station: %pM\n", + sta->addr); + } + + mutex_unlock(&ar->conf_mutex); +} + static int ath10k_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2858,9 +3418,22 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; int max_num_peers; int ret = 0; + if (old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) { + memset(arsta, 0, sizeof(*arsta)); + arsta->arvif = arvif; + INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); + } + + /* cancel must be done outside the mutex to avoid deadlock */ + if ((old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) + cancel_work_sync(&arsta->update_wk); + mutex_lock(&ar->conf_mutex); if (old_state == IEEE80211_STA_NOTEXIST && @@ -2875,7 +3448,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, max_num_peers = TARGET_NUM_PEERS; if (ar->num_peers >= max_num_peers) { - ath10k_warn("Number of peers exceeded: peers number %d (max peers %d)\n", + ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n", ar->num_peers, max_num_peers); ret = -ENOBUFS; goto exit; @@ -2887,7 +3460,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", + ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n", sta->addr, arvif->vdev_id, ret); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { @@ -2899,8 +3472,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arvif->vdev_id, sta->addr); ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); if (ret) - ath10k_warn("Failed to delete peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); + ath10k_warn("failed to delete peer %pM for vdev %d: %i\n", + sta->addr, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) ath10k_bss_disassoc(hw, vif); @@ -2914,10 +3487,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n", sta->addr); - ret = ath10k_station_assoc(ar, arvif, sta); + ret = ath10k_station_assoc(ar, arvif, sta, false); if (ret) - ath10k_warn("Failed to associate station: %pM\n", - sta->addr); + ath10k_warn("failed to associate station %pM for vdev %i: %i\n", + sta->addr, arvif->vdev_id, ret); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH && (vif->type == NL80211_IFTYPE_AP || @@ -2930,8 +3503,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ret = ath10k_station_disassoc(ar, arvif, sta); if (ret) - ath10k_warn("Failed to disassociate station: %pM\n", - sta->addr); + ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n", + sta->addr, arvif->vdev_id, ret); } exit: mutex_unlock(&ar->conf_mutex); @@ -2978,7 +3551,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, WMI_STA_PS_PARAM_UAPSD, arvif->u.sta.uapsd); if (ret) { - ath10k_warn("could not set uapsd params %d\n", ret); + ath10k_warn("failed to set uapsd params: %d\n", ret); goto exit; } @@ -2991,7 +3564,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, WMI_STA_PS_PARAM_RX_WAKE_POLICY, value); if (ret) - ath10k_warn("could not set rx wake param %d\n", ret); + ath10k_warn("failed to set rx wake param: %d\n", ret); exit: return ret; @@ -3041,13 +3614,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, /* FIXME: FW accepts wmm params per hw, not per vif */ ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params); if (ret) { - ath10k_warn("could not set wmm params %d\n", ret); + ath10k_warn("failed to set wmm params: %d\n", ret); goto exit; } ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd); if (ret) - ath10k_warn("could not set sta uapsd %d\n", ret); + ath10k_warn("failed to set sta uapsd: %d\n", ret); exit: mutex_unlock(&ar->conf_mutex); @@ -3100,7 +3673,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = ath10k_start_scan(ar, &arg); if (ret) { - ath10k_warn("could not start roc scan (%d)\n", ret); + ath10k_warn("failed to start roc scan: %d\n", ret); spin_lock_bh(&ar->data_lock); ar->scan.in_progress = false; spin_unlock_bh(&ar->data_lock); @@ -3109,7 +3682,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ); if (ret == 0) { - ath10k_warn("could not switch to channel for roc scan\n"); + ath10k_warn("failed to switch to channel for roc scan\n"); ath10k_abort_scan(ar); ret = -ETIMEDOUT; goto exit; @@ -3150,7 +3723,7 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) ret = ath10k_mac_set_rts(arvif, value); if (ret) { - ath10k_warn("could not set rts threshold for vdev %d (%d)\n", + ath10k_warn("failed to set rts threshold for vdev %d: %d\n", arvif->vdev_id, ret); break; } @@ -3173,7 +3746,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) ret = ath10k_mac_set_rts(arvif, value); if (ret) { - ath10k_warn("could not set fragmentation threshold for vdev %d (%d)\n", + ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n", arvif->vdev_id, ret); break; } @@ -3183,7 +3756,8 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ath10k *ar = hw->priv; bool skip; @@ -3212,7 +3786,8 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) }), ATH10K_FLUSH_TIMEOUT_HZ); if (ret <= 0 || skip) - ath10k_warn("tx not flushed\n"); + ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n", + skip, ar->state, ret); skip: mutex_unlock(&ar->conf_mutex); @@ -3234,37 +3809,33 @@ static int ath10k_suspend(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; int ret; - ar->is_target_paused = false; + mutex_lock(&ar->conf_mutex); - ret = ath10k_wmi_pdev_suspend_target(ar); + ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND); if (ret) { - ath10k_warn("could not suspend target (%d)\n", ret); - return 1; - } - - ret = wait_event_interruptible_timeout(ar->event_queue, - ar->is_target_paused == true, - 1 * HZ); - if (ret < 0) { - ath10k_warn("suspend interrupted (%d)\n", ret); - goto resume; - } else if (ret == 0) { - ath10k_warn("suspend timed out - target pause event never came\n"); - goto resume; + if (ret == -ETIMEDOUT) + goto resume; + ret = 1; + goto exit; } ret = ath10k_hif_suspend(ar); if (ret) { - ath10k_warn("could not suspend hif (%d)\n", ret); + ath10k_warn("failed to suspend hif: %d\n", ret); goto resume; } - return 0; + ret = 0; + goto exit; resume: ret = ath10k_wmi_pdev_resume_target(ar); if (ret) - ath10k_warn("could not resume target (%d)\n", ret); - return 1; + ath10k_warn("failed to resume target: %d\n", ret); + + ret = 1; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; } static int ath10k_resume(struct ieee80211_hw *hw) @@ -3272,19 +3843,26 @@ static int ath10k_resume(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; int ret; + mutex_lock(&ar->conf_mutex); + ret = ath10k_hif_resume(ar); if (ret) { - ath10k_warn("could not resume hif (%d)\n", ret); - return 1; + ath10k_warn("failed to resume hif: %d\n", ret); + ret = 1; + goto exit; } ret = ath10k_wmi_pdev_resume_target(ar); if (ret) { - ath10k_warn("could not resume target (%d)\n", ret); - return 1; + ath10k_warn("failed to resume target: %d\n", ret); + ret = 1; + goto exit; } - return 0; + ret = 0; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; } #endif @@ -3575,7 +4153,8 @@ static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask, static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, u8 fixed_rate, - u8 fixed_nss) + u8 fixed_nss, + u8 force_sgi) { struct ath10k *ar = arvif->ar; u32 vdev_param; @@ -3584,17 +4163,21 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, mutex_lock(&ar->conf_mutex); if (arvif->fixed_rate == fixed_rate && - arvif->fixed_nss == fixed_nss) + arvif->fixed_nss == fixed_nss && + arvif->force_sgi == force_sgi) goto exit; if (fixed_rate == WMI_FIXED_RATE_NONE) ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n"); + if (force_sgi) + ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n"); + vdev_param = ar->wmi.vdev_param->fixed_rate; ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, fixed_rate); if (ret) { - ath10k_warn("Could not set fixed_rate param 0x%02x: %d\n", + ath10k_warn("failed to set fixed rate param 0x%02x: %d\n", fixed_rate, ret); ret = -EINVAL; goto exit; @@ -3607,7 +4190,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, vdev_param, fixed_nss); if (ret) { - ath10k_warn("Could not set fixed_nss param %d: %d\n", + ath10k_warn("failed to set fixed nss param %d: %d\n", fixed_nss, ret); ret = -EINVAL; goto exit; @@ -3615,6 +4198,19 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, arvif->fixed_nss = fixed_nss; + vdev_param = ar->wmi.vdev_param->sgi; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + force_sgi); + + if (ret) { + ath10k_warn("failed to set sgi param %d: %d\n", + force_sgi, ret); + ret = -EINVAL; + goto exit; + } + + arvif->force_sgi = force_sgi; + exit: mutex_unlock(&ar->conf_mutex); return ret; @@ -3629,6 +4225,11 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, enum ieee80211_band band = ar->hw->conf.chandef.chan->band; u8 fixed_rate = WMI_FIXED_RATE_NONE; u8 fixed_nss = ar->num_rf_chains; + u8 force_sgi; + + force_sgi = mask->control[band].gi; + if (force_sgi == NL80211_TXRATE_FORCE_LGI) + return -EINVAL; if (!ath10k_default_bitrate_mask(ar, band, mask)) { if (!ath10k_get_fixed_rate_nss(mask, band, @@ -3637,7 +4238,96 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, return -EINVAL; } - return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss); + if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) { + ath10k_warn("failed to force SGI usage for default rate settings\n"); + return -EINVAL; + } + + return ath10k_set_fixed_rate_param(arvif, fixed_rate, + fixed_nss, force_sgi); +} + +static void ath10k_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ + struct ath10k *ar = hw->priv; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + u32 bw, smps; + + spin_lock_bh(&ar->data_lock); + + ath10k_dbg(ATH10K_DBG_MAC, + "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", + sta->addr, changed, sta->bandwidth, sta->rx_nss, + sta->smps_mode); + + if (changed & IEEE80211_RC_BW_CHANGED) { + bw = WMI_PEER_CHWIDTH_20MHZ; + + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_20: + bw = WMI_PEER_CHWIDTH_20MHZ; + break; + case IEEE80211_STA_RX_BW_40: + bw = WMI_PEER_CHWIDTH_40MHZ; + break; + case IEEE80211_STA_RX_BW_80: + bw = WMI_PEER_CHWIDTH_80MHZ; + break; + case IEEE80211_STA_RX_BW_160: + ath10k_warn("Invalid bandwith %d in rc update for %pM\n", + sta->bandwidth, sta->addr); + bw = WMI_PEER_CHWIDTH_20MHZ; + break; + } + + arsta->bw = bw; + } + + if (changed & IEEE80211_RC_NSS_CHANGED) + arsta->nss = sta->rx_nss; + + if (changed & IEEE80211_RC_SMPS_CHANGED) { + smps = WMI_PEER_SMPS_PS_NONE; + + switch (sta->smps_mode) { + case IEEE80211_SMPS_AUTOMATIC: + case IEEE80211_SMPS_OFF: + smps = WMI_PEER_SMPS_PS_NONE; + break; + case IEEE80211_SMPS_STATIC: + smps = WMI_PEER_SMPS_STATIC; + break; + case IEEE80211_SMPS_DYNAMIC: + smps = WMI_PEER_SMPS_DYNAMIC; + break; + case IEEE80211_SMPS_NUM_MODES: + ath10k_warn("Invalid smps %d in sta rc update for %pM\n", + sta->smps_mode, sta->addr); + smps = WMI_PEER_SMPS_PS_NONE; + break; + } + + arsta->smps = smps; + } + + arsta->changed |= changed; + + spin_unlock_bh(&ar->data_lock); + + ieee80211_queue_work(hw, &arsta->update_wk); +} + +static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + /* + * FIXME: Return 0 for time being. Need to figure out whether FW + * has the API to fetch 64-bit local TSF + */ + + return 0; } static const struct ieee80211_ops ath10k_ops = { @@ -3660,9 +4350,13 @@ static const struct ieee80211_ops ath10k_ops = { .set_frag_threshold = ath10k_set_frag_threshold, .flush = ath10k_flush, .tx_last_beacon = ath10k_tx_last_beacon, + .set_antenna = ath10k_set_antenna, + .get_antenna = ath10k_get_antenna, .restart_complete = ath10k_restart_complete, .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_set_bitrate_mask, + .sta_rc_update = ath10k_sta_rc_update, + .get_tsf = ath10k_get_tsf, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, @@ -3939,7 +4633,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id) ath10k_get_arvif_iter, &arvif_iter); if (!arvif_iter.arvif) { - ath10k_warn("No VIF found for VDEV: %d\n", vdev_id); + ath10k_warn("No VIF found for vdev %d\n", vdev_id); return NULL; } @@ -4006,6 +4700,18 @@ int ath10k_mac_register(struct ath10k *ar) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + /* TODO: Have to deal with 2x2 chips if/when the come out. */ + ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK; + ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK; + } else { + ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK; + ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK; + } + + ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask; + ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask; + if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features)) ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | @@ -4019,8 +4725,8 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_SUPPORTS_STATIC_SMPS | - IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_AP_LINK_PS; + IEEE80211_HW_AP_LINK_PS | + IEEE80211_HW_SPECTRUM_MGMT; /* MSDU can have HTT TX fragment pushed in front. The additional 4 * bytes is used for padding/alignment if necessary. */ @@ -4038,10 +4744,12 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; ar->hw->vif_data_size = sizeof(struct ath10k_vif); + ar->hw->sta_data_size = sizeof(struct ath10k_sta); ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ar->hw->wiphy->max_remain_on_channel_duration = 5000; ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; @@ -4070,19 +4778,19 @@ int ath10k_mac_register(struct ath10k *ar) NL80211_DFS_UNSET); if (!ar->dfs_detector) - ath10k_warn("dfs pattern detector init failed\n"); + ath10k_warn("failed to initialise DFS pattern detector\n"); } ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ath10k_reg_notifier); if (ret) { - ath10k_err("Regulatory initialization failed\n"); + ath10k_err("failed to initialise regulatory: %i\n", ret); goto err_free; } ret = ieee80211_register_hw(ar->hw); if (ret) { - ath10k_err("ieee80211 registration failed: %d\n", ret); + ath10k_err("failed to register ieee80211: %d\n", ret); goto err_free; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 29fd197d1fd..d0004d59c97 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -39,15 +39,28 @@ enum ath10k_pci_irq_mode { ATH10K_PCI_IRQ_MSI = 2, }; -static unsigned int ath10k_target_ps; +enum ath10k_pci_reset_mode { + ATH10K_PCI_RESET_AUTO = 0, + ATH10K_PCI_RESET_WARM_ONLY = 1, +}; + +static unsigned int ath10k_pci_target_ps; static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO; +static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO; -module_param(ath10k_target_ps, uint, 0644); -MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option"); +module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644); +MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option"); module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)"); +module_param_named(reset_mode, ath10k_pci_reset_mode, uint, 0644); +MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); + +/* how long wait to wait for target to initialise, in ms */ +#define ATH10K_PCI_TARGET_WAIT 3000 +#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 + #define QCA988X_2_0_DEVICE_ID (0x003c) static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { @@ -58,13 +71,12 @@ static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = { static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address, u32 *data); -static void ath10k_pci_process_ce(struct ath10k *ar); static int ath10k_pci_post_rx(struct ath10k *ar); static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, int num); static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); -static void ath10k_pci_stop_ce(struct ath10k *ar); -static int ath10k_pci_device_reset(struct ath10k *ar); +static int ath10k_pci_cold_reset(struct ath10k *ar); +static int ath10k_pci_warm_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); @@ -73,7 +85,6 @@ static void ath10k_pci_free_irq(struct ath10k *ar); static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); -static void ath10k_pci_cleanup_ce(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -348,9 +359,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, * 2) Buffer in DMA-able space */ orig_nbytes = nbytes; - data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev, - orig_nbytes, - &ce_data_base); + data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, + orig_nbytes, + &ce_data_base, + GFP_ATOMIC); if (!data_buf) { ret = -ENOMEM; @@ -444,12 +456,12 @@ done: __le32_to_cpu(((__le32 *)data_buf)[i]); } } else - ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", - __func__, address); + ath10k_warn("failed to read diag value at 0x%x: %d\n", + address, ret); if (data_buf) - pci_free_consistent(ar_pci->pdev, orig_nbytes, - data_buf, ce_data_base); + dma_free_coherent(ar->dev, orig_nbytes, data_buf, + ce_data_base); return ret; } @@ -492,9 +504,10 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * 2) Buffer in DMA-able space */ orig_nbytes = nbytes; - data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev, - orig_nbytes, - &ce_data_base); + data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, + orig_nbytes, + &ce_data_base, + GFP_ATOMIC); if (!data_buf) { ret = -ENOMEM; goto done; @@ -590,13 +603,13 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, done: if (data_buf) { - pci_free_consistent(ar_pci->pdev, orig_nbytes, data_buf, - ce_data_base); + dma_free_coherent(ar->dev, orig_nbytes, data_buf, + ce_data_base); } if (ret != 0) - ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", __func__, - address); + ath10k_warn("failed to write diag value at 0x%x: %d\n", + address, ret); return ret; } @@ -678,34 +691,12 @@ void ath10k_do_pci_sleep(struct ath10k *ar) } } -/* - * FIXME: Handle OOM properly. - */ -static inline -struct ath10k_pci_compl *get_free_compl(struct ath10k_pci_pipe *pipe_info) -{ - struct ath10k_pci_compl *compl = NULL; - - spin_lock_bh(&pipe_info->pipe_lock); - if (list_empty(&pipe_info->compl_free)) { - ath10k_warn("Completion buffers are full\n"); - goto exit; - } - compl = list_first_entry(&pipe_info->compl_free, - struct ath10k_pci_compl, list); - list_del(&compl->list); -exit: - spin_unlock_bh(&pipe_info->pipe_lock); - return compl; -} - /* Called by lower (CE) layer when a send to Target completes. */ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) { struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; - struct ath10k_pci_compl *compl; + struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; void *transfer_context; u32 ce_data; unsigned int nbytes; @@ -714,27 +705,12 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) while (ath10k_ce_completed_send_next(ce_state, &transfer_context, &ce_data, &nbytes, &transfer_id) == 0) { - compl = get_free_compl(pipe_info); - if (!compl) - break; - - compl->state = ATH10K_PCI_COMPL_SEND; - compl->ce_state = ce_state; - compl->pipe_info = pipe_info; - compl->skb = transfer_context; - compl->nbytes = nbytes; - compl->transfer_id = transfer_id; - compl->flags = 0; + /* no need to call tx completion for NULL pointers */ + if (transfer_context == NULL) + continue; - /* - * Add the completion to the processing queue. - */ - spin_lock_bh(&ar_pci->compl_lock); - list_add_tail(&compl->list, &ar_pci->compl_process); - spin_unlock_bh(&ar_pci->compl_lock); + cb->tx_completion(ar, transfer_context, transfer_id); } - - ath10k_pci_process_ce(ar); } /* Called by lower (CE) layer when data is received from the Target. */ @@ -743,82 +719,117 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; - struct ath10k_pci_compl *compl; + struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; struct sk_buff *skb; void *transfer_context; u32 ce_data; - unsigned int nbytes; + unsigned int nbytes, max_nbytes; unsigned int transfer_id; unsigned int flags; + int err; while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, &ce_data, &nbytes, &transfer_id, &flags) == 0) { - compl = get_free_compl(pipe_info); - if (!compl) - break; - - compl->state = ATH10K_PCI_COMPL_RECV; - compl->ce_state = ce_state; - compl->pipe_info = pipe_info; - compl->skb = transfer_context; - compl->nbytes = nbytes; - compl->transfer_id = transfer_id; - compl->flags = flags; + err = ath10k_pci_post_rx_pipe(pipe_info, 1); + if (unlikely(err)) { + /* FIXME: retry */ + ath10k_warn("failed to replenish CE rx ring %d: %d\n", + pipe_info->pipe_num, err); + } skb = transfer_context; + max_nbytes = skb->len + skb_tailroom(skb); dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - /* - * Add the completion to the processing queue. - */ - spin_lock_bh(&ar_pci->compl_lock); - list_add_tail(&compl->list, &ar_pci->compl_process); - spin_unlock_bh(&ar_pci->compl_lock); - } + max_nbytes, DMA_FROM_DEVICE); + + if (unlikely(max_nbytes < nbytes)) { + ath10k_warn("rxed more than expected (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; + } - ath10k_pci_process_ce(ar); + skb_put(skb, nbytes); + cb->rx_completion(ar, skb, pipe_info->pipe_num); + } } -/* Send the first nbytes bytes of the buffer */ -static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id, - unsigned int transfer_id, - unsigned int bytes, struct sk_buff *nbuf) +static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) { - struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe_id]); - struct ath10k_ce_pipe *ce_hdl = pipe_info->ce_hdl; - unsigned int len; - u32 flags = 0; - int ret; + struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id]; + struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl; + struct ath10k_ce_ring *src_ring = ce_pipe->src_ring; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; + int err, i = 0; + + spin_lock_bh(&ar_pci->ce_lock); + + nentries_mask = src_ring->nentries_mask; + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + if (unlikely(CE_RING_DELTA(nentries_mask, + write_index, sw_index - 1) < n_items)) { + err = -ENOBUFS; + goto err; + } - len = min(bytes, nbuf->len); - bytes -= len; + for (i = 0; i < n_items - 1; i++) { + ath10k_dbg(ATH10K_DBG_PCI, + "pci tx item %d paddr 0x%08x len %d n_items %d\n", + i, items[i].paddr, items[i].len, n_items); + ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", + items[i].vaddr, items[i].len); + + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + CE_SEND_FLAG_GATHER); + if (err) + goto err; + } - if (len & 3) - ath10k_warn("skb not aligned to 4-byte boundary (%d)\n", len); + /* `i` is equal to `n_items -1` after for() */ ath10k_dbg(ATH10K_DBG_PCI, - "pci send data vaddr %p paddr 0x%llx len %d as %d bytes\n", - nbuf->data, (unsigned long long) skb_cb->paddr, - nbuf->len, len); - ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, - "ath10k tx: data: ", - nbuf->data, nbuf->len); - - ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id, - flags); - if (ret) - ath10k_warn("failed to send sk_buff to CE: %p\n", nbuf); + "pci tx item %d paddr 0x%08x len %d n_items %d\n", + i, items[i].paddr, items[i].len, n_items); + ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ", + items[i].vaddr, items[i].len); + + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + 0); + if (err) + goto err; - return ret; + spin_unlock_bh(&ar_pci->ce_lock); + return 0; + +err: + for (; i > 0; i--) + __ath10k_ce_send_revert(ce_pipe); + + spin_unlock_bh(&ar_pci->ce_lock); + return err; } static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n"); + return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl); } @@ -833,9 +844,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ath10k_err("firmware crashed!\n"); ath10k_err("hardware name %s version 0x%x\n", ar->hw_params.name, ar->target_version); - ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major, - ar->fw_version_minor, ar->fw_version_release, - ar->fw_version_build); + ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); ret = ath10k_pci_diag_read_mem(ar, host_addr, @@ -872,6 +881,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, int force) { + ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n"); + if (!force) { int resources; /* @@ -898,58 +909,12 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar, { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n"); memcpy(&ar_pci->msg_callbacks_current, callbacks, sizeof(ar_pci->msg_callbacks_current)); } -static int ath10k_pci_alloc_compl(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - const struct ce_attr *attr; - struct ath10k_pci_pipe *pipe_info; - struct ath10k_pci_compl *compl; - int i, pipe_num, completions; - - spin_lock_init(&ar_pci->compl_lock); - INIT_LIST_HEAD(&ar_pci->compl_process); - - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - - spin_lock_init(&pipe_info->pipe_lock); - INIT_LIST_HEAD(&pipe_info->compl_free); - - /* Handle Diagnostic CE specially */ - if (pipe_info->ce_hdl == ar_pci->ce_diag) - continue; - - attr = &host_ce_config_wlan[pipe_num]; - completions = 0; - - if (attr->src_nentries) - completions += attr->src_nentries; - - if (attr->dest_nentries) - completions += attr->dest_nentries; - - for (i = 0; i < completions; i++) { - compl = kmalloc(sizeof(*compl), GFP_KERNEL); - if (!compl) { - ath10k_warn("No memory for completion state\n"); - ath10k_pci_cleanup_ce(ar); - return -ENOMEM; - } - - compl->state = ATH10K_PCI_COMPL_FREE; - list_add_tail(&compl->list, &pipe_info->compl_free); - } - } - - return 0; -} - static int ath10k_pci_setup_ce_irq(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -994,147 +959,6 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar) tasklet_kill(&ar_pci->pipe_info[i].intr); } -static void ath10k_pci_stop_ce(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_compl *compl; - struct sk_buff *skb; - - /* Mark pending completions as aborted, so that upper layers free up - * their associated resources */ - spin_lock_bh(&ar_pci->compl_lock); - list_for_each_entry(compl, &ar_pci->compl_process, list) { - skb = compl->skb; - ATH10K_SKB_CB(skb)->is_aborted = true; - } - spin_unlock_bh(&ar_pci->compl_lock); -} - -static void ath10k_pci_cleanup_ce(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_compl *compl, *tmp; - struct ath10k_pci_pipe *pipe_info; - struct sk_buff *netbuf; - int pipe_num; - - /* Free pending completions. */ - spin_lock_bh(&ar_pci->compl_lock); - if (!list_empty(&ar_pci->compl_process)) - ath10k_warn("pending completions still present! possible memory leaks.\n"); - - list_for_each_entry_safe(compl, tmp, &ar_pci->compl_process, list) { - list_del(&compl->list); - netbuf = compl->skb; - dev_kfree_skb_any(netbuf); - kfree(compl); - } - spin_unlock_bh(&ar_pci->compl_lock); - - /* Free unused completions for each pipe. */ - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - - spin_lock_bh(&pipe_info->pipe_lock); - list_for_each_entry_safe(compl, tmp, - &pipe_info->compl_free, list) { - list_del(&compl->list); - kfree(compl); - } - spin_unlock_bh(&pipe_info->pipe_lock); - } -} - -static void ath10k_pci_process_ce(struct ath10k *ar) -{ - struct ath10k_pci *ar_pci = ar->hif.priv; - struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; - struct ath10k_pci_compl *compl; - struct sk_buff *skb; - unsigned int nbytes; - int ret, send_done = 0; - - /* Upper layers aren't ready to handle tx/rx completions in parallel so - * we must serialize all completion processing. */ - - spin_lock_bh(&ar_pci->compl_lock); - if (ar_pci->compl_processing) { - spin_unlock_bh(&ar_pci->compl_lock); - return; - } - ar_pci->compl_processing = true; - spin_unlock_bh(&ar_pci->compl_lock); - - for (;;) { - spin_lock_bh(&ar_pci->compl_lock); - if (list_empty(&ar_pci->compl_process)) { - spin_unlock_bh(&ar_pci->compl_lock); - break; - } - compl = list_first_entry(&ar_pci->compl_process, - struct ath10k_pci_compl, list); - list_del(&compl->list); - spin_unlock_bh(&ar_pci->compl_lock); - - switch (compl->state) { - case ATH10K_PCI_COMPL_SEND: - cb->tx_completion(ar, - compl->skb, - compl->transfer_id); - send_done = 1; - break; - case ATH10K_PCI_COMPL_RECV: - ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1); - if (ret) { - ath10k_warn("failed to post RX buffer for pipe %d: %d\n", - compl->pipe_info->pipe_num, ret); - break; - } - - skb = compl->skb; - nbytes = compl->nbytes; - - ath10k_dbg(ATH10K_DBG_PCI, - "ath10k_pci_ce_recv_data netbuf=%p nbytes=%d\n", - skb, nbytes); - ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, - "ath10k rx: ", skb->data, nbytes); - - if (skb->len + skb_tailroom(skb) >= nbytes) { - skb_trim(skb, 0); - skb_put(skb, nbytes); - cb->rx_completion(ar, skb, - compl->pipe_info->pipe_num); - } else { - ath10k_warn("rxed more than expected (nbytes %d, max %d)", - nbytes, - skb->len + skb_tailroom(skb)); - } - break; - case ATH10K_PCI_COMPL_FREE: - ath10k_warn("free completion cannot be processed\n"); - break; - default: - ath10k_warn("invalid completion state (%d)\n", - compl->state); - break; - } - - compl->state = ATH10K_PCI_COMPL_FREE; - - /* - * Add completion back to the pipe's free list. - */ - spin_lock_bh(&compl->pipe_info->pipe_lock); - list_add_tail(&compl->list, &compl->pipe_info->compl_free); - spin_unlock_bh(&compl->pipe_info->pipe_lock); - } - - spin_lock_bh(&ar_pci->compl_lock); - ar_pci->compl_processing = false; - spin_unlock_bh(&ar_pci->compl_lock); -} - /* TODO - temporary mapping while we have too few CE's */ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, u8 *ul_pipe, @@ -1143,6 +967,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, { int ret = 0; + ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n"); + /* polling for received messages not supported */ *dl_is_polled = 0; @@ -1202,6 +1028,8 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, { int ul_is_polled, dl_is_polled; + ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n"); + (void)ath10k_pci_hif_map_service_to_pipe(ar, ATH10K_HTC_SVC_ID_RSVD_CTRL, ul_pipe, @@ -1303,20 +1131,16 @@ static int ath10k_pci_hif_start(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret, ret_early; + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n"); + ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); - ret = ath10k_pci_alloc_compl(ar); - if (ret) { - ath10k_warn("failed to allocate CE completions: %d\n", ret); - goto err_early_irq; - } - ret = ath10k_pci_request_irq(ar); if (ret) { ath10k_warn("failed to post RX buffers for all pipes: %d\n", ret); - goto err_free_compl; + goto err_early_irq; } ret = ath10k_pci_setup_ce_irq(ar); @@ -1340,10 +1164,6 @@ err_stop: ath10k_ce_disable_interrupts(ar); ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); - ath10k_pci_stop_ce(ar); - ath10k_pci_process_ce(ar); -err_free_compl: - ath10k_pci_cleanup_ce(ar); err_early_irq: /* Though there should be no interrupts (device was reset) * power_down() expects the early IRQ to be installed as per the @@ -1414,18 +1234,10 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf, &ce_data, &nbytes, &id) == 0) { - /* - * Indicate the completion to higer layer to free - * the buffer - */ - - if (!netbuf) { - ath10k_warn("invalid sk_buff on CE %d - NULL pointer. firmware crashed?\n", - ce_hdl->id); + /* no need to call tx completion for NULL pointers */ + if (!netbuf) continue; - } - ATH10K_SKB_CB(netbuf)->is_aborted = true; ar_pci->msg_callbacks_current.tx_completion(ar, netbuf, id); @@ -1456,18 +1268,10 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar) static void ath10k_pci_ce_deinit(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info; - int pipe_num; + int i; - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - if (pipe_info->ce_hdl) { - ath10k_ce_deinit(pipe_info->ce_hdl); - pipe_info->ce_hdl = NULL; - pipe_info->buf_sz = 0; - } - } + for (i = 0; i < CE_COUNT; i++) + ath10k_ce_deinit_pipe(ar, i); } static void ath10k_pci_hif_stop(struct ath10k *ar) @@ -1475,7 +1279,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n"); + + if (WARN_ON(!ar_pci->started)) + return; ret = ath10k_ce_disable_interrupts(ar); if (ret) @@ -1483,7 +1290,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_free_irq(ar); ath10k_pci_kill_tasklet(ar); - ath10k_pci_stop_ce(ar); ret = ath10k_pci_request_early_irq(ar); if (ret) @@ -1493,8 +1299,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * not DMA nor interrupt. We process the leftovers and then free * everything else up. */ - ath10k_pci_process_ce(ar); - ath10k_pci_cleanup_ce(ar); ath10k_pci_buffer_cleanup(ar); /* Make the sure the device won't access any structures on the host by @@ -1502,7 +1306,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * configuration during init. If ringbuffers are freed and the device * were to access them this could lead to memory corruption on the * host. */ - ath10k_pci_device_reset(ar); + ath10k_pci_warm_reset(ar); ar_pci->started = 0; } @@ -1923,30 +1727,49 @@ static int ath10k_pci_init_config(struct ath10k *ar) return 0; } +static int ath10k_pci_alloc_ce(struct ath10k *ar) +{ + int i, ret; + + for (i = 0; i < CE_COUNT; i++) { + ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); + if (ret) { + ath10k_err("failed to allocate copy engine pipe %d: %d\n", + i, ret); + return ret; + } + } + + return 0; +} + +static void ath10k_pci_free_ce(struct ath10k *ar) +{ + int i; + for (i = 0; i < CE_COUNT; i++) + ath10k_ce_free_pipe(ar, i); +} static int ath10k_pci_ce_init(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pipe_info; const struct ce_attr *attr; - int pipe_num; + int pipe_num, ret; for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { pipe_info = &ar_pci->pipe_info[pipe_num]; + pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num]; pipe_info->pipe_num = pipe_num; pipe_info->hif_ce_state = ar; attr = &host_ce_config_wlan[pipe_num]; - pipe_info->ce_hdl = ath10k_ce_init(ar, pipe_num, attr); - if (pipe_info->ce_hdl == NULL) { - ath10k_err("failed to initialize CE for pipe: %d\n", - pipe_num); - - /* It is safe to call it here. It checks if ce_hdl is - * valid for each pipe */ - ath10k_pci_ce_deinit(ar); - return -1; + ret = ath10k_ce_init_pipe(ar, pipe_num, attr); + if (ret) { + ath10k_err("failed to initialize copy engine pipe %d: %d\n", + pipe_num, ret); + return ret; } if (pipe_num == CE_COUNT - 1) { @@ -1967,16 +1790,15 @@ static int ath10k_pci_ce_init(struct ath10k *ar) static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - u32 fw_indicator_address, fw_indicator; + u32 fw_indicator; ath10k_pci_wake(ar); - fw_indicator_address = ar_pci->fw_indicator_address; - fw_indicator = ath10k_pci_read32(ar, fw_indicator_address); + fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); if (fw_indicator & FW_IND_EVENT_PENDING) { /* ACK: clear Target-side pending event */ - ath10k_pci_write32(ar, fw_indicator_address, + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, fw_indicator & ~FW_IND_EVENT_PENDING); if (ar_pci->started) { @@ -1993,7 +1815,115 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(ar); } -static int ath10k_pci_hif_power_up(struct ath10k *ar) +/* this function effectively clears target memory controller assert line */ +static void ath10k_pci_warm_reset_si0(struct ath10k *ar) +{ + u32 val; + + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_SI0_RST_MASK); + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + + msleep(10); + + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val & ~SOC_RESET_CONTROL_SI0_RST_MASK); + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + + msleep(10); +} + +static int ath10k_pci_warm_reset(struct ath10k *ar) +{ + int ret = 0; + u32 val; + + ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n"); + + ret = ath10k_do_pci_wake(ar); + if (ret) { + ath10k_err("failed to wake up target: %d\n", ret); + return ret; + } + + /* debug */ + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CAUSE_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CPU_INTR_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", + val); + + /* disable pending irqs */ + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS, 0); + + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CLR_ADDRESS, ~0); + + msleep(100); + + /* clear fw indicator */ + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); + + /* clear target LF timer interrupts */ + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_LF_TIMER_CONTROL0_ADDRESS); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + + SOC_LF_TIMER_CONTROL0_ADDRESS, + val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); + + /* reset CE */ + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CE_RST_MASK); + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + msleep(10); + + /* unreset CE */ + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val & ~SOC_RESET_CONTROL_CE_RST_MASK); + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + msleep(10); + + ath10k_pci_warm_reset_si0(ar); + + /* debug */ + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CAUSE_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CPU_INTR_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", + val); + + /* CPU warm reset */ + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); + + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val); + + msleep(100); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n"); + + ath10k_do_pci_sleep(ar); + return ret; +} + +static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); const char *irq_mode; @@ -2009,7 +1939,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) * is in an unexpected state. We try to catch that here in order to * reset the Target and retry the probe. */ - ret = ath10k_pci_device_reset(ar); + if (cold_reset) + ret = ath10k_pci_cold_reset(ar); + else + ret = ath10k_pci_warm_reset(ar); + if (ret) { ath10k_err("failed to reset target: %d\n", ret); goto err; @@ -2069,7 +2003,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) irq_mode = "legacy"; if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) - ath10k_info("pci irq %s\n", irq_mode); + ath10k_info("pci irq %s irq_mode %d reset_mode %d\n", + irq_mode, ath10k_pci_irq_mode, + ath10k_pci_reset_mode); return 0; @@ -2079,7 +2015,7 @@ err_deinit_irq: ath10k_pci_deinit_irq(ar); err_ce: ath10k_pci_ce_deinit(ar); - ath10k_pci_device_reset(ar); + ath10k_pci_warm_reset(ar); err_ps: if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); @@ -2087,16 +2023,75 @@ err: return ret; } +static int ath10k_pci_hif_power_up_warm(struct ath10k *ar) +{ + int i, ret; + + /* + * Sometime warm reset succeeds after retries. + * + * FIXME: It might be possible to tune ath10k_pci_warm_reset() to work + * at first try. + */ + for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { + ret = __ath10k_pci_hif_power_up(ar, false); + if (ret == 0) + break; + + ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n", + i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret); + } + + return ret; +} + +static int ath10k_pci_hif_power_up(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n"); + + /* + * Hardware CUS232 version 2 has some issues with cold reset and the + * preferred (and safer) way to perform a device reset is through a + * warm reset. + * + * Warm reset doesn't always work though so fall back to cold reset may + * be necessary. + */ + ret = ath10k_pci_hif_power_up_warm(ar); + if (ret) { + ath10k_warn("failed to power up target using warm reset: %d\n", + ret); + + if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) + return ret; + + ath10k_warn("trying cold reset\n"); + + ret = __ath10k_pci_hif_power_up(ar, true); + if (ret) { + ath10k_err("failed to power up target using cold reset too (%d)\n", + ret); + return ret; + } + } + + return 0; +} + static void ath10k_pci_hif_power_down(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n"); + ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); ath10k_pci_deinit_irq(ar); - ath10k_pci_device_reset(ar); - ath10k_pci_ce_deinit(ar); + ath10k_pci_warm_reset(ar); + if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); } @@ -2151,7 +2146,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) #endif static const struct ath10k_hif_ops ath10k_pci_hif_ops = { - .send_head = ath10k_pci_hif_send_head, + .tx_sg = ath10k_pci_hif_tx_sg, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, .start = ath10k_pci_hif_start, .stop = ath10k_pci_hif_stop, @@ -2244,7 +2239,6 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) static void ath10k_pci_early_irq_tasklet(unsigned long data) { struct ath10k *ar = (struct ath10k *)data; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); u32 fw_ind; int ret; @@ -2255,14 +2249,11 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data) return; } - fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address); + fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); if (fw_ind & FW_IND_EVENT_PENDING) { - ath10k_pci_write32(ar, ar_pci->fw_indicator_address, + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, fw_ind & ~FW_IND_EVENT_PENDING); - - /* Some structures are unavailable during early boot or at - * driver teardown so just print that the device has crashed. */ - ath10k_warn("device crashed - no diagnostics available\n"); + ath10k_pci_hif_dump_area(ar); } ath10k_pci_sleep(ar); @@ -2411,11 +2402,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar) /* Try MSI-X */ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { ar_pci->num_msi_intrs = MSI_NUM_REQUEST; - ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); - if (ret == 0) - return 0; + ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs, + ar_pci->num_msi_intrs); if (ret > 0) - pci_disable_msi(ar_pci->pdev); + return 0; /* fall-through */ } @@ -2482,6 +2472,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) case MSI_NUM_REQUEST: pci_disable_msi(ar_pci->pdev); return 0; + default: + pci_disable_msi(ar_pci->pdev); } ath10k_warn("unknown irq configuration upon deinit\n"); @@ -2491,43 +2483,81 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) static int ath10k_pci_wait_for_target_init(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int wait_limit = 300; /* 3 sec */ + unsigned long timeout; int ret; + u32 val; + + ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); ret = ath10k_pci_wake(ar); if (ret) { - ath10k_err("failed to wake up target: %d\n", ret); + ath10k_err("failed to wake up target for init: %d\n", ret); return ret; } - while (wait_limit-- && - !(ioread32(ar_pci->mem + FW_INDICATOR_ADDRESS) & - FW_IND_INITIALIZED)) { + timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT); + + do { + val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val); + + /* target should never return this */ + if (val == 0xffffffff) + continue; + + /* the device has crashed so don't bother trying anymore */ + if (val & FW_IND_EVENT_PENDING) + break; + + if (val & FW_IND_INITIALIZED) + break; + if (ar_pci->num_msi_intrs == 0) /* Fix potential race by repeating CORE_BASE writes */ - iowrite32(PCIE_INTR_FIRMWARE_MASK | - PCIE_INTR_CE_MASK_ALL, - ar_pci->mem + (SOC_CORE_BASE_ADDRESS | - PCIE_INTR_ENABLE_ADDRESS)); + ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS, + PCIE_INTR_FIRMWARE_MASK | + PCIE_INTR_CE_MASK_ALL); + mdelay(10); - } + } while (time_before(jiffies, timeout)); - if (wait_limit < 0) { - ath10k_err("target stalled\n"); + if (val == 0xffffffff) { + ath10k_err("failed to read device register, device is gone\n"); ret = -EIO; goto out; } + if (val & FW_IND_EVENT_PENDING) { + ath10k_warn("device has crashed during init\n"); + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, + val & ~FW_IND_EVENT_PENDING); + ath10k_pci_hif_dump_area(ar); + ret = -ECOMM; + goto out; + } + + if (!(val & FW_IND_INITIALIZED)) { + ath10k_err("failed to receive initialized event from target: %08x\n", + val); + ret = -ETIMEDOUT; + goto out; + } + + ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n"); + out: ath10k_pci_sleep(ar); return ret; } -static int ath10k_pci_device_reset(struct ath10k *ar) +static int ath10k_pci_cold_reset(struct ath10k *ar) { int i, ret; u32 val; + ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n"); + ret = ath10k_do_pci_wake(ar); if (ret) { ath10k_err("failed to wake up target: %d\n", @@ -2559,6 +2589,9 @@ static int ath10k_pci_device_reset(struct ath10k *ar) } ath10k_do_pci_sleep(ar); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n"); + return 0; } @@ -2590,7 +2623,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, struct ath10k_pci *ar_pci; u32 lcr_val, chip_id; - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n"); ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL); if (ar_pci == NULL) @@ -2609,7 +2642,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_ar_pci; } - if (ath10k_target_ps) + if (ath10k_pci_target_ps) set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features); ath10k_pci_dump_features(ar_pci); @@ -2622,23 +2655,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev, } ar_pci->ar = ar; - ar_pci->fw_indicator_address = FW_INDICATOR_ADDRESS; atomic_set(&ar_pci->keep_awake_count, 0); pci_set_drvdata(pdev, ar); - /* - * Without any knowledge of the Host, the Target may have been reset or - * power cycled and its Config Space may no longer reflect the PCI - * address space that was assigned earlier by the PCI infrastructure. - * Refresh it now. - */ - ret = pci_assign_resource(pdev, BAR_NUM); - if (ret) { - ath10k_err("failed to assign PCI space: %d\n", ret); - goto err_ar; - } - ret = pci_enable_device(pdev); if (ret) { ath10k_err("failed to enable PCI device: %d\n", ret); @@ -2700,16 +2720,24 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ath10k_do_pci_sleep(ar); + ret = ath10k_pci_alloc_ce(ar); + if (ret) { + ath10k_err("failed to allocate copy engine pipes: %d\n", ret); + goto err_iomap; + } + ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem); ret = ath10k_core_register(ar, chip_id); if (ret) { ath10k_err("failed to register driver core: %d\n", ret); - goto err_iomap; + goto err_free_ce; } return 0; +err_free_ce: + ath10k_pci_free_ce(ar); err_iomap: pci_iounmap(pdev, mem); err_master: @@ -2732,7 +2760,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) struct ath10k *ar = pci_get_drvdata(pdev); struct ath10k_pci *ar_pci; - ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); + ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n"); if (!ar) return; @@ -2742,9 +2770,8 @@ static void ath10k_pci_remove(struct pci_dev *pdev) if (!ar_pci) return; - tasklet_kill(&ar_pci->msi_fw_err); - ath10k_core_unregister(ar); + ath10k_pci_free_ce(ar); pci_iounmap(pdev, ar_pci->mem); pci_release_region(pdev, BAR_NUM); @@ -2786,6 +2813,5 @@ module_exit(ath10k_pci_exit); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_OTP_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index a4f32038c44..dfdebb4157a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -43,23 +43,6 @@ struct bmi_xfer { u32 resp_len; }; -enum ath10k_pci_compl_state { - ATH10K_PCI_COMPL_FREE = 0, - ATH10K_PCI_COMPL_SEND, - ATH10K_PCI_COMPL_RECV, -}; - -struct ath10k_pci_compl { - struct list_head list; - enum ath10k_pci_compl_state state; - struct ath10k_ce_pipe *ce_state; - struct ath10k_pci_pipe *pipe_info; - struct sk_buff *skb; - unsigned int nbytes; - unsigned int transfer_id; - unsigned int flags; -}; - /* * PCI-specific Target state * @@ -175,9 +158,6 @@ struct ath10k_pci_pipe { /* protects compl_free and num_send_allowed */ spinlock_t pipe_lock; - /* List of free CE completion slots */ - struct list_head compl_free; - struct ath10k_pci *ar_pci; struct tasklet_struct intr; }; @@ -205,21 +185,10 @@ struct ath10k_pci { atomic_t keep_awake_count; bool verified_awake; - /* List of CE completions to be processed */ - struct list_head compl_process; - - /* protects compl_processing and compl_process */ - spinlock_t compl_lock; - - bool compl_processing; - struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; struct ath10k_hif_cb msg_callbacks_current; - /* Target address used to signal a pending firmware event */ - u32 fw_indicator_address; - /* Copy Engine used for Diagnostic Accesses */ struct ath10k_ce_pipe *ce_diag; diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 74f45fa6f42..82669a77e55 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -51,7 +51,8 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ieee80211_tx_info *info; struct ath10k_skb_cb *skb_cb; struct sk_buff *msdu; - int ret; + + lockdep_assert_held(&htt->tx_lock); ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack); @@ -65,12 +66,12 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, msdu = htt->pending_tx[tx_done->msdu_id]; skb_cb = ATH10K_SKB_CB(msdu); - ret = ath10k_skb_unmap(dev, msdu); - if (ret) - ath10k_warn("data skb unmap failed (%d)\n", ret); + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); - if (skb_cb->htt.frag_len) - skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); + if (skb_cb->htt.txbuf) + dma_pool_free(htt->tx_pool, + skb_cb->htt.txbuf, + skb_cb->htt.txbuf_paddr); ath10k_report_offchan_tx(htt->ar, msdu); @@ -92,190 +93,11 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, /* we do not own the msdu anymore */ exit: - spin_lock_bh(&htt->tx_lock); htt->pending_tx[tx_done->msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); __ath10k_htt_tx_dec_pending(htt); if (htt->num_pending_tx == 0) wake_up(&htt->empty_tx_wq); - spin_unlock_bh(&htt->tx_lock); -} - -static const u8 rx_legacy_rate_idx[] = { - 3, /* 0x00 - 11Mbps */ - 2, /* 0x01 - 5.5Mbps */ - 1, /* 0x02 - 2Mbps */ - 0, /* 0x03 - 1Mbps */ - 3, /* 0x04 - 11Mbps */ - 2, /* 0x05 - 5.5Mbps */ - 1, /* 0x06 - 2Mbps */ - 0, /* 0x07 - 1Mbps */ - 10, /* 0x08 - 48Mbps */ - 8, /* 0x09 - 24Mbps */ - 6, /* 0x0A - 12Mbps */ - 4, /* 0x0B - 6Mbps */ - 11, /* 0x0C - 54Mbps */ - 9, /* 0x0D - 36Mbps */ - 7, /* 0x0E - 18Mbps */ - 5, /* 0x0F - 9Mbps */ -}; - -static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info, - enum ieee80211_band band, - struct ieee80211_rx_status *status) -{ - u8 cck, rate, rate_idx, bw, sgi, mcs, nss; - u8 info0 = info->rate.info0; - u32 info1 = info->rate.info1; - u32 info2 = info->rate.info2; - u8 preamble = 0; - - /* Check if valid fields */ - if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) - return; - - preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); - - switch (preamble) { - case HTT_RX_LEGACY: - cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; - rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); - rate_idx = 0; - - if (rate < 0x08 || rate > 0x0F) - break; - - switch (band) { - case IEEE80211_BAND_2GHZ: - if (cck) - rate &= ~BIT(3); - rate_idx = rx_legacy_rate_idx[rate]; - break; - case IEEE80211_BAND_5GHZ: - rate_idx = rx_legacy_rate_idx[rate]; - /* We are using same rate table registering - HW - ath10k_rates[]. In case of 5GHz skip - CCK rates, so -4 here */ - rate_idx -= 4; - break; - default: - break; - } - - status->rate_idx = rate_idx; - break; - case HTT_RX_HT: - case HTT_RX_HT_WITH_TXBF: - /* HT-SIG - Table 20-11 in info1 and info2 */ - mcs = info1 & 0x1F; - nss = mcs >> 3; - bw = (info1 >> 7) & 1; - sgi = (info2 >> 7) & 1; - - status->rate_idx = mcs; - status->flag |= RX_FLAG_HT; - if (sgi) - status->flag |= RX_FLAG_SHORT_GI; - if (bw) - status->flag |= RX_FLAG_40MHZ; - break; - case HTT_RX_VHT: - case HTT_RX_VHT_WITH_TXBF: - /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 - TODO check this */ - mcs = (info2 >> 4) & 0x0F; - nss = ((info1 >> 10) & 0x07) + 1; - bw = info1 & 3; - sgi = info2 & 1; - - status->rate_idx = mcs; - status->vht_nss = nss; - - if (sgi) - status->flag |= RX_FLAG_SHORT_GI; - - switch (bw) { - /* 20MHZ */ - case 0: - break; - /* 40MHZ */ - case 1: - status->flag |= RX_FLAG_40MHZ; - break; - /* 80MHZ */ - case 2: - status->flag |= RX_FLAG_80MHZ; - } - - status->flag |= RX_FLAG_VHT; - break; - default: - break; - } -} - -void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) -{ - struct ieee80211_rx_status *status; - struct ieee80211_channel *ch; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)info->skb->data; - - status = IEEE80211_SKB_RXCB(info->skb); - memset(status, 0, sizeof(*status)); - - if (info->encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) { - status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | - RX_FLAG_MMIC_STRIPPED; - hdr->frame_control = __cpu_to_le16( - __le16_to_cpu(hdr->frame_control) & - ~IEEE80211_FCTL_PROTECTED); - } - - if (info->mic_err) - status->flag |= RX_FLAG_MMIC_ERROR; - - if (info->fcs_err) - status->flag |= RX_FLAG_FAILED_FCS_CRC; - - if (info->amsdu_more) - status->flag |= RX_FLAG_AMSDU_MORE; - - status->signal = info->signal; - - spin_lock_bh(&ar->data_lock); - ch = ar->scan_channel; - if (!ch) - ch = ar->rx_channel; - spin_unlock_bh(&ar->data_lock); - - if (!ch) { - ath10k_warn("no channel configured; ignoring frame!\n"); - dev_kfree_skb_any(info->skb); - return; - } - - process_rx_rates(ar, info, ch->band, status); - status->band = ch->band; - status->freq = ch->center_freq; - - ath10k_dbg(ATH10K_DBG_DATA, - "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u\n", - info->skb, - info->skb->len, - status->flag == 0 ? "legacy" : "", - status->flag & RX_FLAG_HT ? "ht" : "", - status->flag & RX_FLAG_VHT ? "vht" : "", - status->flag & RX_FLAG_40MHZ ? "40" : "", - status->flag & RX_FLAG_80MHZ ? "80" : "", - status->flag & RX_FLAG_SHORT_GI ? "sgi " : "", - status->rate_idx, - status->vht_nss, - status->freq, - status->band); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", - info->skb->data, info->skb->len); - - ieee80211_rx(ar->hw, info->skb); } struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, @@ -378,7 +200,8 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt, spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, ev->peer_id); if (!peer) { - ath10k_warn("unknown peer id %d\n", ev->peer_id); + ath10k_warn("peer-unmap-event: unknown peer id %d\n", + ev->peer_id); goto exit; } diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h index 356dc9c04c9..aee3e20058f 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.h +++ b/drivers/net/wireless/ath/ath10k/txrx.h @@ -21,7 +21,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, const struct htt_tx_done *tx_done); -void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info); struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, const u8 *addr); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 712a606a080..4b7782a529a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE, .p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE, .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, - .ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED, + .ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID, .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, .peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID, .wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID, @@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_PDEV_PARAM_PMF_QOS, .arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE, - .arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, .dcs = WMI_PDEV_PARAM_DCS, .ani_enable = WMI_PDEV_PARAM_ANI_ENABLE, .ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD, @@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .bcnflt_stats_update_period = WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, - .arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, - .arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, + .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, .dcs = WMI_10X_PDEV_PARAM_DCS, .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, @@ -561,7 +559,6 @@ err_pull: static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) { - struct wmi_bcn_tx_arg arg = {0}; int ret; lockdep_assert_held(&arvif->ar->data_lock); @@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) if (arvif->beacon == NULL) return; - arg.vdev_id = arvif->vdev_id; - arg.tx_rate = 0; - arg.tx_power = 0; - arg.bcn = arvif->beacon->data; - arg.bcn_len = arvif->beacon->len; + if (arvif->beacon_sent) + return; - ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); + ret = ath10k_wmi_beacon_send_ref_nowait(arvif); if (ret) return; - dev_kfree_skb_any(arvif->beacon); - arvif->beacon = NULL; + /* We need to retain the arvif->beacon reference for DMA unmapping and + * freeing the skbuff later. */ + arvif->beacon_sent = true; } static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, @@ -644,6 +639,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) struct sk_buff *wmi_skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int len; + u32 buf_len = skb->len; u16 fc; hdr = (struct ieee80211_hdr *)skb->data; @@ -653,6 +649,15 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) return -EINVAL; len = sizeof(cmd->hdr) + skb->len; + + if ((ieee80211_is_action(hdr->frame_control) || + ieee80211_is_deauth(hdr->frame_control) || + ieee80211_is_disassoc(hdr->frame_control)) && + ieee80211_has_protected(hdr->frame_control)) { + len += IEEE80211_CCMP_MIC_LEN; + buf_len += IEEE80211_CCMP_MIC_LEN; + } + len = round_up(len, 4); wmi_skb = ath10k_wmi_alloc_skb(len); @@ -664,7 +669,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id); cmd->hdr.tx_rate = 0; cmd->hdr.tx_power = 0; - cmd->hdr.buf_len = __cpu_to_le32((u32)(skb->len)); + cmd->hdr.buf_len = __cpu_to_le32(buf_len); memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN); memcpy(cmd->buf, skb->data, skb->len); @@ -962,10 +967,16 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) * frames with Protected Bit set. */ if (ieee80211_has_protected(hdr->frame_control) && !ieee80211_is_auth(hdr->frame_control)) { - status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED | - RX_FLAG_MMIC_STRIPPED; - hdr->frame_control = __cpu_to_le16(fc & + status->flag |= RX_FLAG_DECRYPTED; + + if (!ieee80211_is_action(hdr->frame_control) && + !ieee80211_is_deauth(hdr->frame_control) && + !ieee80211_is_disassoc(hdr->frame_control)) { + status->flag |= RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; + hdr->frame_control = __cpu_to_le16(fc & ~IEEE80211_FCTL_PROTECTED); + } } ath10k_dbg(ATH10K_DBG_MGMT, @@ -1116,7 +1127,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n"); + struct wmi_peer_sta_kickout_event *ev; + struct ieee80211_sta *sta; + + ev = (struct wmi_peer_sta_kickout_event *)skb->data; + + ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", + ev->peer_macaddr.addr); + + rcu_read_lock(); + + sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); + if (!sta) { + ath10k_warn("Spurious quick kickout for STA %pM\n", + ev->peer_macaddr.addr); + goto exit; + } + + ieee80211_report_low_ack(sta, 10); + +exit: + rcu_read_unlock(); } /* @@ -1217,6 +1248,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); + if (tim->dtim_count == 0) { + ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; + + if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1) + ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; + } + ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", tim->dtim_count, tim->dtim_period, tim->bitmap_ctrl, pvm_len); @@ -1338,15 +1376,12 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct wmi_bcn_info *bcn_info; struct ath10k_vif *arvif; struct sk_buff *bcn; - int vdev_id = 0; - - ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); + int ret, vdev_id = 0; ev = (struct wmi_host_swba_event *)skb->data; map = __le32_to_cpu(ev->vdev_map); - ath10k_dbg(ATH10K_DBG_MGMT, "host swba:\n" - "-vdev map 0x%x\n", + ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", ev->vdev_map); for (; map; map >>= 1, vdev_id++) { @@ -1363,12 +1398,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) bcn_info = &ev->bcn_info[i]; ath10k_dbg(ATH10K_DBG_MGMT, - "-bcn_info[%d]:\n" - "--tim_len %d\n" - "--tim_mcast %d\n" - "--tim_changed %d\n" - "--tim_num_ps_pending %d\n" - "--tim_bitmap 0x%08x%08x%08x%08x\n", + "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n", i, __le32_to_cpu(bcn_info->tim_info.tim_len), __le32_to_cpu(bcn_info->tim_info.tim_mcast), @@ -1385,6 +1415,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) continue; } + /* There are no completions for beacons so wait for next SWBA + * before telling mac80211 to decrement CSA counter + * + * Once CSA counter is completed stop sending beacons until + * actual channel switch is done */ + if (arvif->vif->csa_active && + ieee80211_csa_is_complete(arvif->vif)) { + ieee80211_csa_finish(arvif->vif); + continue; + } + bcn = ieee80211_beacon_get(ar->hw, arvif->vif); if (!bcn) { ath10k_warn("could not get mac80211 beacon\n"); @@ -1396,15 +1437,35 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); spin_lock_bh(&ar->data_lock); + if (arvif->beacon) { - ath10k_warn("SWBA overrun on vdev %d\n", - arvif->vdev_id); + if (!arvif->beacon_sent) + ath10k_warn("SWBA overrun on vdev %d\n", + arvif->vdev_id); + + dma_unmap_single(arvif->ar->dev, + ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); dev_kfree_skb_any(arvif->beacon); + arvif->beacon = NULL; + } + + ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev, + bcn->data, bcn->len, + DMA_TO_DEVICE); + ret = dma_mapping_error(arvif->ar->dev, + ATH10K_SKB_CB(bcn)->paddr); + if (ret) { + ath10k_warn("failed to map beacon: %d\n", ret); + dev_kfree_skb_any(bcn); + goto skip; } arvif->beacon = bcn; + arvif->beacon_sent = false; ath10k_wmi_tx_beacon_nowait(arvif); +skip: spin_unlock_bh(&ar->data_lock); } } @@ -2031,11 +2092,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN); ath10k_dbg(ATH10K_DBG_WMI, - "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", + "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n", __le32_to_cpu(ev->sw_version), __le32_to_cpu(ev->abi_version), ev->mac_addr.addr, - __le32_to_cpu(ev->status)); + __le32_to_cpu(ev->status), skb->len, sizeof(*ev)); complete(&ar->wmi.unified_ready); return 0; @@ -2314,7 +2375,7 @@ void ath10k_wmi_detach(struct ath10k *ar) ar->wmi.num_mem_chunks = 0; } -int ath10k_wmi_connect_htc_service(struct ath10k *ar) +int ath10k_wmi_connect(struct ath10k *ar) { int status; struct ath10k_htc_svc_conn_req conn_req; @@ -2342,8 +2403,9 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar) return 0; } -int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g) +static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, + u16 rd2g, u16 rd5g, u16 ctl2g, + u16 ctl5g) { struct wmi_pdev_set_regdomain_cmd *cmd; struct sk_buff *skb; @@ -2367,6 +2429,46 @@ int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, ar->wmi.cmd->pdev_set_regdomain_cmdid); } +static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, + u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + struct wmi_pdev_set_regdomain_cmd_10x *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data; + cmd->reg_domain = __cpu_to_le32(rd); + cmd->reg_domain_2G = __cpu_to_le32(rd2g); + cmd->reg_domain_5G = __cpu_to_le32(rd5g); + cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g); + cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g); + cmd->dfs_domain = __cpu_to_le32(dfs_reg); + + ath10k_dbg(ATH10K_DBG_WMI, + "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n", + rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_regdomain_cmdid); +} + +int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, + u16 rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) + return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g, + ctl2g, ctl5g, dfs_reg); + else + return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g, + ctl2g, ctl5g); +} + int ath10k_wmi_pdev_set_channel(struct ath10k *ar, const struct wmi_channel_arg *arg) { @@ -2403,7 +2505,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, ar->wmi.cmd->pdev_set_channel_cmdid); } -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) +int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) { struct wmi_pdev_suspend_cmd *cmd; struct sk_buff *skb; @@ -2413,7 +2515,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) return -ENOMEM; cmd = (struct wmi_pdev_suspend_cmd *)skb->data; - cmd->suspend_opt = WMI_PDEV_SUSPEND; + cmd->suspend_opt = __cpu_to_le32(suspend_opt); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); } @@ -3342,7 +3444,6 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, ci->max_power = ch->max_power; ci->reg_power = ch->max_reg_power; ci->antenna_max = ch->max_antenna_gain; - ci->antenna_max = 0; /* mode & flags share storage */ ci->mode = ch->mode; @@ -3406,30 +3507,47 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); ath10k_dbg(ATH10K_DBG_WMI, - "wmi peer assoc vdev %d addr %pM\n", - arg->vdev_id, arg->addr); + "wmi peer assoc vdev %d addr %pM (%s)\n", + arg->vdev_id, arg->addr, + arg->peer_reassoc ? "reassociate" : "new"); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); } -int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_arg *arg) +/* This function assumes the beacon is already DMA mapped */ +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) { - struct wmi_bcn_tx_cmd *cmd; + struct wmi_bcn_tx_ref_cmd *cmd; struct sk_buff *skb; + struct sk_buff *beacon = arvif->beacon; + struct ath10k *ar = arvif->ar; + struct ieee80211_hdr *hdr; int ret; + u16 fc; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); if (!skb) return -ENOMEM; - cmd = (struct wmi_bcn_tx_cmd *)skb->data; - cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); - cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate); - cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); - cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); - memcpy(cmd->bcn, arg->bcn, arg->bcn_len); + hdr = (struct ieee80211_hdr *)beacon->data; + fc = le16_to_cpu(hdr->frame_control); + + cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); + cmd->data_len = __cpu_to_le32(beacon->len); + cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); + cmd->msdu_id = 0; + cmd->frame_control = __cpu_to_le32(fc); + cmd->flags = 0; + + if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); + + if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); + + ret = ath10k_wmi_cmd_send_nowait(ar, skb, + ar->wmi.cmd->pdev_send_bcn_cmdid); - ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid); if (ret) dev_kfree_skb(skb); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4b5e7d3d32b..e93df2c1041 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -198,16 +198,6 @@ struct wmi_mac_addr { } __packed; } __packed; -/* macro to convert MAC address from WMI word format to char array */ -#define WMI_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr, c_macaddr) do { \ - (c_macaddr)[0] = ((pwmi_mac_addr)->word0) & 0xff; \ - (c_macaddr)[1] = (((pwmi_mac_addr)->word0) >> 8) & 0xff; \ - (c_macaddr)[2] = (((pwmi_mac_addr)->word0) >> 16) & 0xff; \ - (c_macaddr)[3] = (((pwmi_mac_addr)->word0) >> 24) & 0xff; \ - (c_macaddr)[4] = ((pwmi_mac_addr)->word1) & 0xff; \ - (c_macaddr)[5] = (((pwmi_mac_addr)->word1) >> 8) & 0xff; \ - } while (0) - struct wmi_cmd_map { u32 init_cmdid; u32 start_scan_cmdid; @@ -1265,7 +1255,7 @@ struct wmi_resource_config { */ __le32 rx_decap_mode; - /* what is the maximum scan requests than can be queued */ + /* what is the maximum number of scan requests that can be queued */ __le32 scan_max_pending_reqs; /* maximum VDEV that could use BMISS offload */ @@ -1450,7 +1440,7 @@ struct wmi_resource_config_10x { */ __le32 rx_decap_mode; - /* what is the maximum scan requests than can be queued */ + /* what is the maximum number of scan requests that can be queued */ __le32 scan_max_pending_reqs; /* maximum VDEV that could use BMISS offload */ @@ -2185,6 +2175,31 @@ struct wmi_pdev_set_regdomain_cmd { __le32 conformance_test_limit_5G; } __packed; +enum wmi_dfs_region { + /* Uninitialized dfs domain */ + WMI_UNINIT_DFS_DOMAIN = 0, + + /* FCC3 dfs domain */ + WMI_FCC_DFS_DOMAIN = 1, + + /* ETSI dfs domain */ + WMI_ETSI_DFS_DOMAIN = 2, + + /*Japan dfs domain */ + WMI_MKK4_DFS_DOMAIN = 3, +}; + +struct wmi_pdev_set_regdomain_cmd_10x { + __le32 reg_domain; + __le32 reg_domain_2G; + __le32 reg_domain_5G; + __le32 conformance_test_limit_2G; + __le32 conformance_test_limit_5G; + + /* dfs domain from wmi_dfs_region */ + __le32 dfs_domain; +} __packed; + /* Command to set/unset chip in quiet mode */ struct wmi_pdev_set_quiet_cmd { /* period in TUs */ @@ -2210,6 +2225,19 @@ enum ath10k_protmode { ATH10K_PROT_RTSCTS = 2, /* RTS-CTS */ }; +enum wmi_rtscts_profile { + WMI_RTSCTS_FOR_NO_RATESERIES = 0, + WMI_RTSCTS_FOR_SECOND_RATESERIES, + WMI_RTSCTS_ACROSS_SW_RETRIES +}; + +#define WMI_RTSCTS_ENABLED 1 +#define WMI_RTSCTS_SET_MASK 0x0f +#define WMI_RTSCTS_SET_LSB 0 + +#define WMI_RTSCTS_PROFILE_MASK 0xf0 +#define WMI_RTSCTS_PROFILE_LSB 4 + enum wmi_beacon_gen_mode { WMI_BEACON_STAGGERED_MODE = 0, WMI_BEACON_BURST_MODE = 1 @@ -2277,7 +2305,6 @@ struct wmi_pdev_param_map { u32 bcnflt_stats_update_period; u32 pmf_qos; u32 arp_ac_override; - u32 arpdhcp_ac_override; u32 dcs; u32 ani_enable; u32 ani_poll_period; @@ -2296,9 +2323,9 @@ struct wmi_pdev_param_map { #define WMI_PDEV_PARAM_UNSUPPORTED 0 enum wmi_pdev_param { - /* TX chian mask */ + /* TX chain mask */ WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1, - /* RX chian mask */ + /* RX chain mask */ WMI_PDEV_PARAM_RX_CHAIN_MASK, /* TX power limit for 2G Radio */ WMI_PDEV_PARAM_TXPOWER_LIMIT2G, @@ -2683,6 +2710,9 @@ struct wal_dbg_tx_stats { /* wal pdev resets */ __le32 pdev_resets; + /* frames dropped due to non-availability of stateless TIDs */ + __le32 stateless_tid_alloc_failure; + __le32 phy_underrun; /* MPDU is more than txop limit */ @@ -2739,13 +2769,21 @@ enum wmi_stats_id { WMI_REQUEST_AP_STAT = 0x02 }; +struct wlan_inst_rssi_args { + __le16 cfg_retry_count; + __le16 retry_count; +}; + struct wmi_request_stats_cmd { __le32 stats_id; - /* - * Space to add parameters like - * peer mac addr - */ + __le32 vdev_id; + + /* peer MAC address */ + struct wmi_mac_addr peer_macaddr; + + /* Instantaneous RSSI arguments */ + struct wlan_inst_rssi_args inst_rssi_args; } __packed; /* Suspend option */ @@ -2796,7 +2834,18 @@ struct wmi_stats_event { * PDEV statistics * TODO: add all PDEV stats here */ -struct wmi_pdev_stats { +struct wmi_pdev_stats_old { + __le32 chan_nf; /* Channel noise floor */ + __le32 tx_frame_count; /* TX frame count */ + __le32 rx_frame_count; /* RX frame count */ + __le32 rx_clear_count; /* rx clear count */ + __le32 cycle_count; /* cycle count */ + __le32 phy_err_count; /* Phy error count */ + __le32 chan_tx_pwr; /* channel tx power */ + struct wal_dbg_stats wal; /* WAL dbg stats */ +} __packed; + +struct wmi_pdev_stats_10x { __le32 chan_nf; /* Channel noise floor */ __le32 tx_frame_count; /* TX frame count */ __le32 rx_frame_count; /* RX frame count */ @@ -2805,6 +2854,12 @@ struct wmi_pdev_stats { __le32 phy_err_count; /* Phy error count */ __le32 chan_tx_pwr; /* channel tx power */ struct wal_dbg_stats wal; /* WAL dbg stats */ + __le32 ack_rx_bad; + __le32 rts_bad; + __le32 rts_good; + __le32 fcs_bad; + __le32 no_beacons; + __le32 mib_int_count; } __packed; /* @@ -2819,10 +2874,17 @@ struct wmi_vdev_stats { * peer statistics. * TODO: add more stats */ -struct wmi_peer_stats { +struct wmi_peer_stats_old { + struct wmi_mac_addr peer_macaddr; + __le32 peer_rssi; + __le32 peer_tx_rate; +} __packed; + +struct wmi_peer_stats_10x { struct wmi_mac_addr peer_macaddr; __le32 peer_rssi; __le32 peer_tx_rate; + __le32 peer_rx_rate; } __packed; struct wmi_vdev_create_cmd { @@ -3403,6 +3465,24 @@ struct wmi_bcn_tx_arg { const void *bcn; }; +enum wmi_bcn_tx_ref_flags { + WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1, + WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2, +}; + +struct wmi_bcn_tx_ref_cmd { + __le32 vdev_id; + __le32 data_len; + /* physical address of the frame - dma pointer */ + __le32 data_ptr; + /* id for host to track */ + __le32 msdu_id; + /* frame ctrl to setup PPDU desc */ + __le32 frame_control; + /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */ + __le32 flags; +} __packed; + /* Beacon filter */ #define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ #define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ @@ -3859,6 +3939,12 @@ enum wmi_peer_smps_state { WMI_PEER_SMPS_DYNAMIC = 0x2 }; +enum wmi_peer_chwidth { + WMI_PEER_CHWIDTH_20MHZ = 0, + WMI_PEER_CHWIDTH_40MHZ = 1, + WMI_PEER_CHWIDTH_80MHZ = 2, +}; + enum wmi_peer_param { WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ WMI_PEER_AMPDU = 0x2, @@ -4039,6 +4125,10 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +struct wmi_peer_sta_kickout_event { + struct wmi_mac_addr peer_macaddr; +} __packed; + #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) /* FIXME: empirically extrapolated */ @@ -4169,13 +4259,14 @@ void ath10k_wmi_detach(struct ath10k *ar); int ath10k_wmi_wait_for_service_ready(struct ath10k *ar); int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); -int ath10k_wmi_connect_htc_service(struct ath10k *ar); +int ath10k_wmi_connect(struct ath10k *ar); int ath10k_wmi_pdev_set_channel(struct ath10k *ar, const struct wmi_channel_arg *); -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar); +int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt); int ath10k_wmi_pdev_resume_target(struct ath10k *ar); int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g); + u16 rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg); int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value); int ath10k_wmi_cmd_init(struct ath10k *ar); int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *); @@ -4219,8 +4310,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, enum wmi_ap_ps_peer_param param_id, u32 value); int ath10k_wmi_scan_chan_list(struct ath10k *ar, const struct wmi_scan_chan_list_arg *arg); -int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_arg *arg); +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif); int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, const struct wmi_pdev_set_wmm_params_arg *arg); int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index ef35da84f63..4b18434ba69 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -751,6 +751,9 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(ah->dev, bf->skbaddr)) + return -ENOSPC; + ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates, ARRAY_SIZE(bf->rates)); diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 4ee01f65423..afb23b3cc7b 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) survey->channel = conf->chandef.chan; survey->noise = ah->ah_noise_floor; survey->filled = SURVEY_INFO_NOISE_DBM | + SURVEY_INFO_IN_USE | SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX | diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 1a2973b7acf..0fce1c76638 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -3709,8 +3709,8 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), AR5K_TPC); } else { - ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | - AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); + ath5k_hw_reg_write(ah, AR5K_TUNE_MAX_TXPOWER, + AR5K_PHY_TXPOWER_RATE_MAX); } return 0; diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index e39e5860a2e..9c125ff083f 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -1,11 +1,19 @@ config ATH6KL tristate "Atheros mobile chipsets support" + depends on CFG80211 + ---help--- + This module adds core support for wireless adapters based on + Atheros AR6003 and AR6004 chipsets. You still need separate + bus drivers for USB and SDIO to be able to use real devices. + + If you choose to build it as a module, it will be called + ath6kl_core. Please note that AR6002 and AR6001 are not + supported by this driver. config ATH6KL_SDIO tristate "Atheros ath6kl SDIO support" depends on ATH6KL depends on MMC - depends on CFG80211 ---help--- This module adds support for wireless adapters based on Atheros AR6003 and AR6004 chipsets running over SDIO. If you @@ -17,25 +25,31 @@ config ATH6KL_USB tristate "Atheros ath6kl USB support" depends on ATH6KL depends on USB - depends on CFG80211 ---help--- This module adds support for wireless adapters based on - Atheros AR6004 chipset running over USB. This is still under - implementation and it isn't functional. If you choose to - build it as a module, it will be called ath6kl_usb. + Atheros AR6004 chipset and chipsets based on it running over + USB. If you choose to build it as a module, it will be + called ath6kl_usb. config ATH6KL_DEBUG bool "Atheros ath6kl debugging" depends on ATH6KL ---help--- - Enables debug support + Enables ath6kl debug support, including debug messages + enabled with debug_mask module parameter and debugfs + interface. + + If unsure, say Y to make it easier to debug problems. config ATH6KL_TRACING bool "Atheros ath6kl tracing support" depends on ATH6KL depends on EVENT_TRACING ---help--- - Select this to ath6kl use tracing infrastructure. + Select this to ath6kl use tracing infrastructure which, for + example, can be enabled with help of trace-cmd. All debug + messages and commands are delivered to using individually + enablable trace points. If unsure, say Y to make it easier to debug problems. @@ -47,3 +61,5 @@ config ATH6KL_REGDOMAIN Enabling this makes it possible to change the regdomain in the firmware. This can be only enabled if regulatory requirements are taken into account. + + If unsure, say N. diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index fd4c89df67e..0e26f4a34fd 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -724,8 +724,9 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to cfg80211\n", bssid); kfree(ie); - } else + } else { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n"); + } return bss; } @@ -790,7 +791,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, if (nw_type & ADHOC_NETWORK) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", nw_type & ADHOC_CREATOR ? "creator" : "joiner"); - cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); + cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL); cfg80211_put_bss(ar->wiphy, bss); return; } @@ -861,13 +862,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, } if (vif->nw_type & ADHOC_NETWORK) { - if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) { + if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in ibss mode\n", __func__); - return; - } - memset(bssid, 0, ETH_ALEN); - cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); return; } @@ -974,7 +971,6 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar, ssid_list[i].flag, ssid_list[i].ssid.ssid_len, ssid_list[i].ssid.ssid); - } /* Make sure no old entries are left behind */ @@ -1763,7 +1759,7 @@ static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi) } static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac, struct station_info *sinfo) + const u8 *mac, struct station_info *sinfo) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -1901,7 +1897,6 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif, /* Configure the patterns that we received from the user. */ for (i = 0; i < wow->n_patterns; i++) { - /* * Convert given nl80211 specific mask value to equivalent * driver specific mask value and send it to the chip along @@ -2854,8 +2849,9 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, if (p.prwise_crypto_type == 0) { p.prwise_crypto_type = NONE_CRYPT; ath6kl_set_cipher(vif, 0, true); - } else if (info->crypto.n_ciphers_pairwise == 1) + } else if (info->crypto.n_ciphers_pairwise == 1) { ath6kl_set_cipher(vif, info->crypto.ciphers_pairwise[0], true); + } switch (info->crypto.cipher_group) { case WLAN_CIPHER_SUITE_WEP40: @@ -2901,7 +2897,6 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, } if (info->inactivity_timeout) { - inactivity_timeout = info->inactivity_timeout; if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) @@ -2979,7 +2974,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac) + const u8 *mac) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -2990,7 +2985,8 @@ static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, } static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac, struct station_parameters *params) + const u8 *mac, + struct station_parameters *params) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; int ret, rssi_thold; + int n_match_sets = request->n_match_sets; + + /* + * If there's a matchset w/o an SSID, then assume it's just for + * the RSSI (nothing else is currently supported) and ignore it. + * The device only supports a global RSSI filter that we set below. + */ + if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len) + n_match_sets = 0; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, request->n_ssids, request->match_sets, - request->n_match_sets); + n_match_sets); if (ret < 0) return ret; - if (!request->n_match_sets) { + if (!n_match_sets) { ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, ALL_BSS_FILTER, 0); if (ret < 0) @@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, ar->fw_capabilities)) { - if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) + if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) rssi_thold = 0; - else if (request->rssi_thold < -127) + else if (request->min_rssi_thold < -127) rssi_thold = -127; else - rssi_thold = request->rssi_thold; + rssi_thold = request->min_rssi_thold; ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, rssi_thold); diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 4b46adbe8c9..b0b65204276 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -45,9 +45,9 @@ module_param(testmode, uint, 0644); module_param(recovery_enable, uint, 0644); module_param(heart_beat_poll, uint, 0644); MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error"); -MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \ - "polling. This also specifies the polling interval in" \ - "msecs. Set reocvery_enable for this to be effective"); +MODULE_PARM_DESC(heart_beat_poll, + "Enable fw error detection periodic polling in msecs - Also set recovery_enable for this to be effective"); + void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index dbfd17d0a5f..55c4064dd50 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -172,7 +172,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_proc_registers *irq_proc_reg, struct ath6kl_irq_enable_reg *irq_enable_reg) { - ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n")); if (irq_proc_reg != NULL) { @@ -219,7 +218,6 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, "GMBOX lookahead alias 1: 0x%x\n", irq_proc_reg->rx_gmbox_lkahd_alias[1]); } - } if (irq_enable_reg != NULL) { @@ -1396,7 +1394,6 @@ static ssize_t ath6kl_create_qos_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath6kl *ar = file->private_data; struct ath6kl_vif *vif; char buf[200]; @@ -1575,7 +1572,6 @@ static ssize_t ath6kl_delete_qos_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath6kl *ar = file->private_data; struct ath6kl_vif *vif; char buf[100]; diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index ca9ba005f28..e194c10d9f0 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -97,8 +97,8 @@ static inline void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_proc_registers *irq_proc_reg, struct ath6kl_irq_enable_reg *irq_en_reg) { - } + static inline void dump_cred_dist_stats(struct htc_target *target) { } diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index fea7709b5dd..18c070850a0 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -37,7 +37,6 @@ static int ath6kl_hif_cp_scat_dma_buf(struct hif_scatter_req *req, buf = req->virt_dma_buf; for (i = 0; i < req->scat_entries; i++) { - if (from_dma) memcpy(req->scat_list[i].buf, buf, req->scat_list[i].len); @@ -116,7 +115,6 @@ static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) le32_to_cpu(regdump_val[i + 2]), le32_to_cpu(regdump_val[i + 3])); } - } static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) @@ -701,5 +699,4 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) fail_setup: return status; - } diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index 61f6b21fb0a..dc6bd8cd9b8 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -197,9 +197,9 @@ struct hif_scatter_req { /* bounce buffer for upper layers to copy to/from */ u8 *virt_dma_buf; - struct hif_scatter_item scat_list[1]; - u32 scat_q_depth; + + struct hif_scatter_item scat_list[0]; }; struct ath6kl_irq_proc_registers { diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 65e5b719093..e481f14b987 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -112,9 +112,9 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, if (cur_ep_dist->endpoint == ENDPOINT_0) continue; - if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) + if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) { cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; - else { + } else { /* * For the remaining data endpoints, we assume that * each cred_per_msg are the same. We use a simple @@ -129,7 +129,6 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, count = (count * 3) >> 2; count = max(count, cur_ep_dist->cred_per_msg); cur_ep_dist->cred_norm = count; - } ath6kl_dbg(ATH6KL_DBG_CREDIT, @@ -549,7 +548,6 @@ static int htc_check_credits(struct htc_target *target, enum htc_endpoint_id eid, unsigned int len, int *req_cred) { - *req_cred = (len > target->tgt_cred_sz) ? DIV_ROUND_UP(len, target->tgt_cred_sz) : 1; @@ -608,7 +606,6 @@ static void ath6kl_htc_tx_pkts_get(struct htc_target *target, unsigned int len; while (true) { - flags = 0; if (list_empty(&endpoint->txq)) @@ -889,7 +886,6 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ac = target->dev->ar->ep2ac_map[endpoint->eid]; while (true) { - if (list_empty(&endpoint->txq)) break; @@ -1190,7 +1186,6 @@ static void ath6kl_htc_mbox_flush_txep(struct htc_target *target, list_add_tail(&packet->list, &container); htc_tx_complete(endpoint, &container); } - } static void ath6kl_htc_flush_txep_all(struct htc_target *target) @@ -1394,7 +1389,6 @@ static int ath6kl_htc_rx_setup(struct htc_target *target, ep_cb = ep->ep_cb; for (j = 0; j < n_msg; j++) { - /* * Reset flag, any packets allocated using the * rx_alloc() API cannot be recycled on @@ -1424,9 +1418,9 @@ static int ath6kl_htc_rx_setup(struct htc_target *target, } } - if (list_empty(&ep->rx_bufq)) + if (list_empty(&ep->rx_bufq)) { packet = NULL; - else { + } else { packet = list_first_entry(&ep->rx_bufq, struct htc_packet, list); list_del(&packet->list); @@ -1487,7 +1481,6 @@ static int ath6kl_htc_rx_alloc(struct htc_target *target, spin_lock_bh(&target->rx_lock); for (i = 0; i < msg; i++) { - htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i]; if (htc_hdr->eid >= ENDPOINT_MAX) { @@ -1708,7 +1701,6 @@ static int htc_parse_trailer(struct htc_target *target, lk_ahd = (struct htc_lookahead_report *) record_buf; if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) && next_lk_ahds) { - ath6kl_dbg(ATH6KL_DBG_HTC, "htc rx lk_ahd found pre_valid 0x%x post_valid 0x%x\n", lk_ahd->pre_valid, lk_ahd->post_valid); @@ -1755,7 +1747,6 @@ static int htc_parse_trailer(struct htc_target *target, } return 0; - } static int htc_proc_trailer(struct htc_target *target, @@ -1776,7 +1767,6 @@ static int htc_proc_trailer(struct htc_target *target, status = 0; while (len > 0) { - if (len < sizeof(struct htc_record_hdr)) { status = -ENOMEM; break; @@ -2098,7 +2088,6 @@ static int ath6kl_htc_rx_fetch(struct htc_target *target, } if (!fetched_pkts) { - packet = list_first_entry(rx_pktq, struct htc_packet, list); @@ -2173,7 +2162,6 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, look_aheads[0] = msg_look_ahead; while (true) { - /* * First lookahead sets the expected endpoint IDs for all * packets in a bundle. @@ -2825,8 +2813,9 @@ static int ath6kl_htc_reset(struct htc_target *target) packet->buf = packet->buf_start; packet->endpoint = ENDPOINT_0; list_add_tail(&packet->list, &target->free_ctrl_rxbuf); - } else + } else { list_add_tail(&packet->list, &target->free_ctrl_txbuf); + } } return 0; diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 67aa924ed8b..756fe52a12c 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -137,7 +137,6 @@ static void get_htc_packet_credit_based(struct htc_target *target, credits_required = 0; } else { - if (ep->cred_dist.credits < credits_required) break; @@ -169,7 +168,6 @@ static void get_htc_packet_credit_based(struct htc_target *target, /* queue this packet into the caller's queue */ list_add_tail(&packet->list, queue); } - } static void get_htc_packet(struct htc_target *target, @@ -279,7 +277,6 @@ static int htc_issue_packets(struct htc_target *target, list_add(&packet->list, pkt_queue); break; } - } if (status != 0) { @@ -385,7 +382,6 @@ 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", __func__, packet); @@ -403,7 +399,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, list_move_tail(&packet->list, &send_queue); } - } if (list_empty(&send_queue)) { @@ -454,7 +449,6 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, * enough transmit resources. */ while (true) { - if (get_queue_depth(&ep->txq) == 0) break; @@ -495,8 +489,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, } spin_lock_bh(&target->tx_lock); - } + /* done with this endpoint, we can clear the count */ ep->tx_proc_cnt = 0; spin_unlock_bh(&target->tx_lock); @@ -1106,7 +1100,6 @@ free_skb: dev_kfree_skb(skb); return status; - } static void htc_flush_rx_queue(struct htc_target *target, @@ -1258,7 +1251,6 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target, tx_alloc = 0; } else { - tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id); if (tx_alloc == 0) { status = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 4f316bdcbab..d5ef211f261 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1192,7 +1192,6 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) if (board_ext_address && ar->fw_board_len == (board_data_size + board_ext_data_size)) { - /* write extended board data */ ath6kl_dbg(ATH6KL_DBG_BOOT, "writing extended board data to 0x%x (%d B)\n", diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 5839fc23bdc..d56554674da 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -571,7 +571,6 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) { - struct ath6kl *ar = vif->ar; vif->profile.ch = cpu_to_le16(channel); @@ -600,7 +599,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) { - struct ath6kl_vif *vif; int res = 0; @@ -692,9 +690,9 @@ void ath6kl_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, bool ismcast) cfg80211_michael_mic_failure(vif->ndev, sta->mac, NL80211_KEYTYPE_PAIRWISE, keyid, tsc, GFP_KERNEL); - } else + } else { ath6kl_cfg80211_tkip_micerr_event(vif, keyid, ismcast); - + } } static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) @@ -1093,8 +1091,9 @@ static int ath6kl_open(struct net_device *dev) if (test_bit(CONNECTED, &vif->flags)) { netif_carrier_on(dev); netif_wake_queue(dev); - } else + } else { netif_carrier_off(dev); + } return 0; } @@ -1146,7 +1145,6 @@ static int ath6kl_set_features(struct net_device *dev, dev->features = features | NETIF_F_RXCSUM; return err; } - } return err; diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 7126bdd4236..339d89f14d3 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -348,7 +348,7 @@ static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio, int i, scat_req_sz, scat_list_sz, size; u8 *virt_buf; - scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item); + scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item); scat_req_sz = sizeof(*s_req) + scat_list_sz; if (!virt_scat) @@ -425,8 +425,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, memcpy(tbuf, buf, len); bounced = true; - } else + } else { tbuf = buf; + } ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len); if ((request & HIF_READ) && bounced) @@ -441,9 +442,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio, struct bus_request *req) { - if (req->scat_req) + if (req->scat_req) { ath6kl_sdio_scat_rw(ar_sdio, req); - else { + } else { void *context; int status; @@ -656,7 +657,6 @@ static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar, list_add_tail(&s_req->list, &ar_sdio->scat_req); spin_unlock_bh(&ar_sdio->scat_lock); - } /* scatter gather read write request */ @@ -674,9 +674,9 @@ static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, "hif-scatter: total len: %d scatter entries: %d\n", scat_req->len, scat_req->scat_entries); - if (request & HIF_SYNCHRONOUS) + if (request & HIF_SYNCHRONOUS) { status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); - else { + } else { spin_lock_bh(&ar_sdio->wr_async_lock); list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq); spin_unlock_bh(&ar_sdio->wr_async_lock); @@ -856,7 +856,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ar->suspend_mode == WLAN_POWER_STATE_WOW || (!ar->suspend_mode && wow)) { - ret = ath6kl_set_sdio_pm_caps(ar); if (ret) goto cut_pwr; @@ -878,7 +877,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP || !ar->suspend_mode || try_deepsleep) { - flags = sdio_get_host_pm_caps(func); if (!(flags & MMC_PM_KEEP_POWER)) goto cut_pwr; @@ -1061,7 +1059,6 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar) timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); while (time_before(jiffies, timeout) && !ar->bmi.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 diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index a580a629a0d..d5eeeae7711 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -289,7 +289,7 @@ struct host_interest { u32 hi_hp_rx_traffic_ratio; /* 0xd8 */ /* test applications flags */ - u32 hi_test_apps_related ; /* 0xdc */ + u32 hi_test_apps_related; /* 0xdc */ /* location of test script */ u32 hi_ota_testscript; /* 0xe0 */ /* location of CAL data */ diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index ebb24045a8a..40432fe7a5d 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -125,8 +125,9 @@ static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn, *flags |= WMI_DATA_HDR_FLAGS_UAPSD; spin_unlock_bh(&conn->psq_lock); return false; - } else if (!conn->apsd_info) + } else if (!conn->apsd_info) { return false; + } if (test_bit(WMM_ENABLED, &vif->flags)) { ether_type = be16_to_cpu(datap->h_proto); @@ -316,8 +317,9 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, cookie = NULL; ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n", skb, skb->len); - } else + } else { cookie = ath6kl_alloc_cookie(ar); + } if (cookie == NULL) { spin_unlock_bh(&ar->lock); @@ -359,7 +361,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) struct ath6kl_vif *vif = netdev_priv(dev); u32 map_no = 0; u16 htc_tag = ATH6KL_DATA_PKT_TAG; - u8 ac = 99 ; /* initialize to unmapped ac */ + u8 ac = 99; /* initialize to unmapped ac */ bool chk_adhoc_ps_mapping = false; int ret; struct wmi_tx_meta_v2 meta_v2; @@ -449,8 +451,9 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) if (ret) goto fail_tx; } - } else + } else { goto fail_tx; + } spin_lock_bh(&ar->lock); @@ -702,7 +705,6 @@ void ath6kl_tx_complete(struct htc_target *target, /* reap completed packets */ while (!list_empty(packet_queue)) { - packet = list_first_entry(packet_queue, struct htc_packet, list); list_del(&packet->list); @@ -1089,8 +1091,9 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, else skb_queue_tail(&rxtid->q, node->skb); node->skb = NULL; - } else + } else { stats->num_hole++; + } rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next); idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); @@ -1211,7 +1214,7 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, return is_queued; spin_lock_bh(&rxtid->lock); - for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { + for (idx = 0; idx < rxtid->hold_q_sz; idx++) { if (rxtid->hold_q[idx].skb) { /* * There is a frame in the queue and no @@ -1265,7 +1268,6 @@ static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif, is_apsdq_empty_at_start = is_apsdq_empty; while ((!is_apsdq_empty) && (num_frames_to_deliver)) { - spin_lock_bh(&conn->psq_lock); skb = skb_dequeue(&conn->apsdq); is_apsdq_empty = skb_queue_empty(&conn->apsdq); @@ -1606,16 +1608,18 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) if (!conn) return; aggr_conn = conn->aggr_conn; - } else + } else { aggr_conn = vif->aggr_cntxt->aggr_conn; + } if (aggr_process_recv_frm(aggr_conn, tid, seq_no, is_amsdu, skb)) { /* aggregation code will handle the skb */ return; } - } else if (!is_broadcast_ether_addr(datap->h_dest)) + } else if (!is_broadcast_ether_addr(datap->h_dest)) { vif->net_stats.multicast++; + } ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); } @@ -1710,8 +1714,9 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no, sta = ath6kl_find_sta_by_aid(vif->ar, aid); if (sta) aggr_conn = sta->aggr_conn; - } else + } else { aggr_conn = vif->aggr_cntxt->aggr_conn; + } if (!aggr_conn) return; @@ -1766,7 +1771,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, skb_queue_head_init(&rxtid->q); spin_lock_init(&rxtid->lock); } - } struct aggr_info *aggr_init(struct ath6kl_vif *vif) @@ -1806,8 +1810,9 @@ void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid_mux) sta = ath6kl_find_sta_by_aid(vif->ar, aid); if (sta) aggr_conn = sta->aggr_conn; - } else + } else { aggr_conn = vif->aggr_cntxt->aggr_conn; + } if (!aggr_conn) return; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index f38ff6a6255..3afc5a463d0 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -24,7 +24,7 @@ /* constants */ #define TX_URB_COUNT 32 #define RX_URB_COUNT 32 -#define ATH6KL_USB_RX_BUFFER_SIZE 1700 +#define ATH6KL_USB_RX_BUFFER_SIZE 4096 /* tx/rx pipes for usb */ enum ATH6KL_USB_PIPE_ID { @@ -236,7 +236,6 @@ static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe) break; kfree(urb_context); } - } static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb) @@ -245,7 +244,6 @@ static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb) for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) ath6kl_usb_free_pipe_resources(&ar_usb->pipes[i]); - } static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb, @@ -481,8 +479,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) * ATH6KL_USB_RX_BUFFER_SIZE); */ - ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = - ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2; + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1; + ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], ATH6KL_USB_RX_BUFFER_SIZE); } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 4f16d79c9eb..4d7f9e4712e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -289,8 +289,9 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) + sizeof(struct ath6kl_llc_snap_hdr), layer2_priority); - } else + } else { usr_pri = layer2_priority & 0x7; + } /* * Queue the EAPOL frames in the same WMM_AC_VO queue @@ -359,8 +360,9 @@ int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb) hdr_size = roundup(sizeof(struct ieee80211_qos_hdr), sizeof(u32)); skb_pull(skb, hdr_size); - } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) + } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) { skb_pull(skb, sizeof(struct ieee80211_hdr_3addr)); + } datap = skb->data; llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap); @@ -914,7 +916,7 @@ ath6kl_get_regpair(u16 regdmn) return NULL; for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regdmn) + if (regDomainPairs[i].reg_domain == regdmn) return ®DomainPairs[i]; } @@ -936,7 +938,6 @@ ath6kl_regd_find_country_by_rd(u16 regdmn) static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) { - struct ath6kl_wmi_regdomain *ev; struct country_code_to_enum_rd *country = NULL; struct reg_dmn_pair_mapping *regpair = NULL; @@ -946,15 +947,14 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) ev = (struct ath6kl_wmi_regdomain *) datap; reg_code = le32_to_cpu(ev->reg_code); - if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) + if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) { country = ath6kl_regd_find_country((u16) reg_code); - else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { - + } else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { regpair = ath6kl_get_regpair((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code); if (regpair) ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", - regpair->regDmnEnum); + regpair->reg_domain); else ath6kl_warn("Regpair not found reg_code 0x%0x\n", reg_code); @@ -1499,7 +1499,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) && (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) { - ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); tsinfo = le16_to_cpu(ts->tsinfo); tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & @@ -1530,7 +1529,6 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len, * for delete qos stream from AP */ else if (reply->cac_indication == CAC_INDICATION_DELETE) { - ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); tsinfo = le16_to_cpu(ts->tsinfo); ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & @@ -2322,7 +2320,7 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index, return ret; } -int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk) +int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk) { struct sk_buff *skb; struct wmi_add_krk_cmd *cmd; @@ -2479,7 +2477,6 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) goto free_data_skb; for (index = 0; index < num_pri_streams; index++) { - if (WARN_ON(!data_sync_bufs[index].skb)) goto free_data_skb; @@ -2704,7 +2701,6 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi) for (i = 0; i < WMM_NUM_AC; i++) { if (stream_exist & (1 << i)) { - /* * FIXME: Is this lock & unlock inside * for loop correct? may need rework. @@ -2870,8 +2866,9 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, if (host_mode == ATH6KL_HOST_MODE_ASLEEP) { ath6kl_wmi_relinquish_implicit_pstream_credits(wmi); cmd->asleep = cpu_to_le32(1); - } else + } else { cmd->awake = cpu_to_le32(1); + } ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HOST_SLEEP_MODE_CMDID, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index b5f226503ba..bb23fc00111 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -898,7 +898,6 @@ struct wmi_start_scan_cmd { * flags here */ enum wmi_scan_ctrl_flags_bits { - /* set if can scan in the connect cmd */ CONNECT_SCAN_CTRL_FLAGS = 0x01, @@ -1068,7 +1067,7 @@ struct wmi_power_mode_cmd { } __packed; /* - * Policy to determnine whether power save failure event should be sent to + * Policy to determine whether power save failure event should be sent to * host during scanning */ enum power_save_fail_event_policy { @@ -2617,7 +2616,7 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index, u8 *key_material, u8 key_op_ctrl, u8 *mac_addr, enum wmi_sync_flag sync_flag); -int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk); +int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk); int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index); int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, u8 if_idx, const u8 *bssid, const u8 *pmkid, bool set); diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 7b96b3e5712..8fcc029a76a 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -120,18 +120,6 @@ config ATH9K_WOW This option enables Wake on Wireless LAN support for certain cards. Currently, AR9462 is supported. -config ATH9K_LEGACY_RATE_CONTROL - bool "Atheros ath9k rate control" - depends on ATH9K - default n - ---help--- - Say Y, if you want to use the ath9k specific rate control - module instead of minstrel_ht. Be warned that there are various - issues with the ath9k RC and minstrel is a more robust algorithm. - Note that even if this option is selected, "ath9k_rate_control" - has to be passed to mac80211 using the module parameter, - ieee80211_default_rc_algo. - config ATH9K_RFKILL bool "Atheros ath9k rfkill support" if EXPERT depends on ATH9K diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index a40e5c5d741..8fcd586d1c3 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -8,7 +8,6 @@ ath9k-y += beacon.o \ antenna.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o -ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o @@ -52,7 +51,10 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o -ath9k_common-y:= common.o +ath9k_common-y:= common.o \ + common-init.o \ + common-beacon.o \ + common-debug.o ath9k_htc-y += htc_hst.o \ hif_usb.o \ diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 2dff2765769..be3eb2a8d60 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -39,6 +39,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = { .name = "qca955x_wmac", .driver_data = AR9300_DEVID_QCA955X, }, + { + .name = "qca953x_wmac", + .driver_data = AR9300_DEVID_AR953X, + }, {}, }; @@ -124,9 +128,6 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->mem = mem; sc->irq = irq; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); - ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index d28923b7435..ba502a2d199 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -155,6 +155,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, ATH9K_ANI_RSSI_THR_LOW, ATH9K_ANI_RSSI_THR_HIGH); + if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_OFDM_DEF_LEVEL) + immunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; + if (!scan) aniState->ofdmNoiseImmunityLevel = immunityLevel; @@ -176,16 +179,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) weak_sig = true; - /* - * OFDM Weak signal detection is always enabled for AP mode. + * Newer chipsets are better at dealing with high PHY error counts - + * keep weak signal detection enabled when no RSSI threshold is + * available to determine if it is needed (mode != STA) */ - if (ah->opmode != NL80211_IFTYPE_AP && - aniState->ofdmWeakSigDetect != weak_sig) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - entry_ofdm->ofdm_weak_signal_on); - } + else if (AR_SREV_9300_20_OR_LATER(ah) && + ah->opmode != NL80211_IFTYPE_STATION) + weak_sig = true; + + /* Older chipsets are more sensitive to high PHY error counts */ + else if (!AR_SREV_9300_20_OR_LATER(ah) && + aniState->ofdmNoiseImmunityLevel >= 8) + weak_sig = false; + + if (aniState->ofdmWeakSigDetect != weak_sig) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + weak_sig); + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; @@ -225,6 +238,9 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW, ATH9K_ANI_RSSI_THR_HIGH); + if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_CCK_DEF_LEVEL) + immunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; + if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW && immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) @@ -308,17 +324,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; - /* only allow a subset of functions in AP mode */ - if (ah->opmode == NL80211_IFTYPE_AP) { - if (IS_CHAN_2GHZ(chan)) { - ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - if (AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function |= ATH9K_ANI_MRC_CCK; - } else - ah->ani_function = 0; - } - ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL, aniState->ofdmNoiseImmunityLevel); cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, @@ -483,10 +488,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath_dbg(common, ANI, "Initialize ANI\n"); - ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; - ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; - ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; - ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + } else { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; + } ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 21e7b83c3f6..c40965b4c1e 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -22,12 +22,16 @@ /* units are errors per second */ #define ATH9K_ANI_OFDM_TRIG_HIGH 3500 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 +#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500 #define ATH9K_ANI_OFDM_TRIG_LOW 400 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 +#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200 #define ATH9K_ANI_CCK_TRIG_HIGH 600 +#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200 #define ATH9K_ANI_CCK_TRIG_LOW 300 +#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100 #define ATH9K_ANI_SPUR_IMMUNE_LVL 3 #define ATH9K_ANI_FIRSTEP_LVL 2 diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ff415e863ee..00fb8badbac 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -26,10 +26,6 @@ static const int firstep_table[] = /* level: 0 1 2 3 4 5 6 7 8 */ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ -static const int cycpwrThr1_table[] = -/* level: 0 1 2 3 4 5 6 7 8 */ - { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */ - /* * register values to turn OFDM weak signal detection OFF */ @@ -921,7 +917,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ar5416AniState *aniState = &ah->ani; - s32 value, value2; + s32 value; switch (cmd & ah->ani_function) { case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ @@ -1008,42 +1004,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_FIRSTEP_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(firstep_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(firstep_table)); - return false; - } - - /* - * make register setting relative to default - * from INI file & cap value - */ - value = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstep; - if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value = ATH9K_SIG_FIRSTEP_SETTING_MAX; + value = level; REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - value); - /* - * we need to set first step low register too - * make register setting relative to default - * from INI file & cap value - */ - value2 = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstepLow; - if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX; - - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, - AR_PHY_FIND_SIG_FIRSTEP_LOW, value2); + AR_PHY_FIND_SIG_FIRSTEP, value); if (level != aniState->firstepLevel) { ath_dbg(common, ANI, @@ -1060,7 +1023,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->firstepLevel, level, ATH9K_ANI_FIRSTEP_LVL, - value2, + value, aniState->iniDef.firstepLow); if (level > aniState->firstepLevel) ah->stats.ast_ani_stepup++; @@ -1073,41 +1036,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(cycpwrThr1_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(cycpwrThr1_table)); - return false; - } - /* - * make register setting relative to default - * from INI file & cap value - */ - value = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1; - if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value = ATH9K_SIG_SPUR_IMM_SETTING_MAX; + value = (level + 1) * 2; REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - value); + AR_PHY_TIMING5_CYCPWR_THR1, value); - /* - * set AR_PHY_EXT_CCA for extension channel - * make register setting relative to default - * from INI file & cap value - */ - value2 = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1Ext; - if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX; - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2); + if (IS_CHAN_HT40(ah->curchan)) + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_TIMING5_CYCPWR_THR1, value); if (level != aniState->spurImmunityLevel) { ath_dbg(common, ANI, @@ -1124,7 +1059,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->spurImmunityLevel, level, ATH9K_ANI_SPUR_IMMUNE_LVL, - value2, + value, aniState->iniDef.cycpwrThr1Ext); if (level > aniState->spurImmunityLevel) ah->stats.ast_ani_spurup++; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 0a6163e9248..c38399bc9aa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -410,7 +410,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index a352128c40a..ac8301ef524 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -23,10 +23,11 @@ #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT #define MAX_MAG_DELTA 11 #define MAX_PHS_DELTA 10 +#define MAXIQCAL 3 struct coeff { - int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; - int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; + int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; + int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; int iqc_coeff[2]; }; @@ -655,9 +656,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (i2_m_q2_a0_d1 > 0x800) i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); - if (i2_p_q2_a0_d1 > 0x1000) - i2_p_q2_a0_d1 = -((0x1fff - i2_p_q2_a0_d1) + 1); - if (iq_corr_a0_d1 > 0x800) iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); @@ -800,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (q_q_coff > 63) q_q_coff = 63; - iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; + iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[0]); @@ -831,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (q_q_coff > 63) q_q_coff = 63; - iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; + iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[1]); @@ -839,7 +837,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, return true; } -static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, +static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL], + int nmeasurement, int max_delta) { int mp_max = -64, max_idx = 0; @@ -848,20 +847,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, /* find min/max mismatch across all calibrated gains */ for (i = 0; i < nmeasurement; i++) { - if (mp_coeff[i] > mp_max) { - mp_max = mp_coeff[i]; + if (mp_coeff[i][0] > mp_max) { + mp_max = mp_coeff[i][0]; max_idx = i; - } else if (mp_coeff[i] < mp_min) { - mp_min = mp_coeff[i]; + } else if (mp_coeff[i][0] < mp_min) { + mp_min = mp_coeff[i][0]; min_idx = i; } } /* find average (exclude max abs value) */ for (i = 0; i < nmeasurement; i++) { - if ((abs(mp_coeff[i]) < abs(mp_max)) || - (abs(mp_coeff[i]) < abs(mp_min))) { - mp_avg += mp_coeff[i]; + if ((abs(mp_coeff[i][0]) < abs(mp_max)) || + (abs(mp_coeff[i][0]) < abs(mp_min))) { + mp_avg += mp_coeff[i][0]; mp_count++; } } @@ -873,7 +872,7 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, if (mp_count) mp_avg /= mp_count; else - mp_avg = mp_coeff[nmeasurement - 1]; + mp_avg = mp_coeff[nmeasurement - 1][0]; /* detect outlier */ if (abs(mp_max - mp_min) > max_delta) { @@ -882,15 +881,16 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, else outlier_idx = min_idx; - mp_coeff[outlier_idx] = mp_avg; + mp_coeff[outlier_idx][0] = mp_avg; } } -static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, - struct coeff *coeff, - bool is_reusable) +static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah, + struct coeff *coeff, + bool is_reusable) { int i, im, nmeasurement; + int magnitude, phase; u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; struct ath9k_hw_cal_data *caldata = ah->caldata; @@ -920,21 +920,30 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, if (nmeasurement > MAX_MEASUREMENT) nmeasurement = MAX_MEASUREMENT; - /* detect outlier only if nmeasurement > 1 */ - if (nmeasurement > 1) { - /* Detect magnitude outlier */ - ar9003_hw_detect_outlier(coeff->mag_coeff[i], - nmeasurement, MAX_MAG_DELTA); - - /* Detect phase outlier */ - ar9003_hw_detect_outlier(coeff->phs_coeff[i], - nmeasurement, MAX_PHS_DELTA); + /* + * Skip normal outlier detection for AR9550. + */ + if (!AR_SREV_9550(ah)) { + /* detect outlier only if nmeasurement > 1 */ + if (nmeasurement > 1) { + /* Detect magnitude outlier */ + ar9003_hw_detect_outlier(coeff->mag_coeff[i], + nmeasurement, + MAX_MAG_DELTA); + + /* Detect phase outlier */ + ar9003_hw_detect_outlier(coeff->phs_coeff[i], + nmeasurement, + MAX_PHS_DELTA); + } } for (im = 0; im < nmeasurement; im++) { + magnitude = coeff->mag_coeff[i][im][0]; + phase = coeff->phs_coeff[i][im][0]; - coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | - ((coeff->phs_coeff[i][im] & 0x7f) << 7); + coeff->iqc_coeff[0] = + (phase & 0x7f) | ((magnitude & 0x7f) << 7); if ((im % 2) == 0) REG_RMW_FIELD(ah, tx_corr_coeff[im][i], @@ -991,7 +1000,63 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) return true; } -static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) +static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah, + struct coeff *coeff, + int i, int nmeasurement) +{ + struct ath_common *common = ath9k_hw_common(ah); + int im, ix, iy, temp; + + for (im = 0; im < nmeasurement; im++) { + for (ix = 0; ix < MAXIQCAL - 1; ix++) { + for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) { + if (coeff->mag_coeff[i][im][iy] < + coeff->mag_coeff[i][im][ix]) { + temp = coeff->mag_coeff[i][im][ix]; + coeff->mag_coeff[i][im][ix] = + coeff->mag_coeff[i][im][iy]; + coeff->mag_coeff[i][im][iy] = temp; + } + if (coeff->phs_coeff[i][im][iy] < + coeff->phs_coeff[i][im][ix]) { + temp = coeff->phs_coeff[i][im][ix]; + coeff->phs_coeff[i][im][ix] = + coeff->phs_coeff[i][im][iy]; + coeff->phs_coeff[i][im][iy] = temp; + } + } + } + coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2]; + coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2]; + + ath_dbg(common, CALIBRATE, + "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n", + i, im, + coeff->mag_coeff[i][im][0], + coeff->phs_coeff[i][im][0]); + } +} + +static bool ar955x_tx_iq_cal_median(struct ath_hw *ah, + struct coeff *coeff, + int iqcal_idx, + int nmeasurement) +{ + int i; + + if ((iqcal_idx + 1) != MAXIQCAL) + return false; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement); + } + + return true; +} + +static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, + int iqcal_idx, + bool is_reusable) { struct ath_common *common = ath9k_hw_common(ah); const u32 txiqcal_status[AR9300_MAX_CHAINS] = { @@ -1004,10 +1069,11 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) AR_PHY_CHAN_INFO_TAB_1, AR_PHY_CHAN_INFO_TAB_2, }; - struct coeff coeff; + static struct coeff coeff; s32 iq_res[6]; int i, im, j; - int nmeasurement; + int nmeasurement = 0; + bool outlier_detect = true; for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (!(ah->txchainmask & (1 << i))) @@ -1065,17 +1131,23 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) goto tx_iqcal_fail; } - coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im] = + coeff.phs_coeff[i][im][iqcal_idx] = + coeff.iqc_coeff[0] & 0x7f; + coeff.mag_coeff[i][im][iqcal_idx] = (coeff.iqc_coeff[0] >> 7) & 0x7f; - if (coeff.mag_coeff[i][im] > 63) - coeff.mag_coeff[i][im] -= 128; - if (coeff.phs_coeff[i][im] > 63) - coeff.phs_coeff[i][im] -= 128; + if (coeff.mag_coeff[i][im][iqcal_idx] > 63) + coeff.mag_coeff[i][im][iqcal_idx] -= 128; + if (coeff.phs_coeff[i][im][iqcal_idx] > 63) + coeff.phs_coeff[i][im][iqcal_idx] -= 128; } } - ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable); + + if (AR_SREV_9550(ah)) + outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff, + iqcal_idx, nmeasurement); + if (outlier_detect) + ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable); return; @@ -1409,7 +1481,7 @@ skip_tx_iqcal: } if (txiqcal_done) - ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); + ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable); else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) ar9003_hw_tx_iq_cal_reload(ah); @@ -1455,14 +1527,38 @@ skip_tx_iqcal: return true; } +static bool do_ar9003_agc_cal(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + bool status; + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + if (!status) { + ath_dbg(common, CALIBRATE, + "offset calibration failed to complete in %d ms," + "noisy environment?\n", + AH_WAIT_TIMEOUT / 1000); + return false; + } + + return true; +} + static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; bool txiqcal_done = false; - bool is_reusable = true, status = true; + bool status = true; bool run_agc_cal = false, sep_iq_cal = false; + int i = 0; /* Use chip chainmask only for calibration */ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); @@ -1485,7 +1581,12 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, * AGC calibration. Specifically, AR9550 in SoC chips. */ if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { - txiqcal_done = true; + if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) { + txiqcal_done = true; + } else { + txiqcal_done = false; + } run_agc_cal = true; } else { sep_iq_cal = true; @@ -1512,27 +1613,37 @@ skip_tx_iqcal: if (AR_SREV_9330_11(ah)) ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); - /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - /* Poll for offset calibration complete */ - status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT); - } + /* + * For non-AR9550 chips, we just trigger AGC calibration + * in the HW, poll for completion and then process + * the results. + * + * For AR955x, we run it multiple times and use + * median IQ correction. + */ + if (!AR_SREV_9550(ah)) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; - if (!status) { - ath_dbg(common, CALIBRATE, - "offset calibration failed to complete in %d ms; noisy environment?\n", - AH_WAIT_TIMEOUT / 1000); - return false; + if (txiqcal_done) + ar9003_hw_tx_iq_cal_post_proc(ah, 0, false); + } else { + if (!txiqcal_done) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; + } else { + for (i = 0; i < MAXIQCAL; i++) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; + ar9003_hw_tx_iq_cal_post_proc(ah, i, false); + } + } + } } - if (txiqcal_done) - ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); - /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b8daff78b9d..235053ba773 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -23,8 +23,8 @@ #define COMP_HDR_LEN 4 #define COMP_CKSUM_LEN 2 -#define LE16(x) __constant_cpu_to_le16(x) -#define LE32(x) __constant_cpu_to_le32(x) +#define LE16(x) cpu_to_le16(x) +#define LE32(x) cpu_to_le32(x) /* Local defines to distinguish between extension and control CTL's */ #define EXT_ADDITIVE (0x8000) @@ -4792,43 +4792,54 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah, tempslope: if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4; + /* * AR955x has tempSlope register for each chain. * Check whether temp_compensation feature is enabled or not. */ if (eep->baseEepHeader.featureEnable & 0x1) { if (frequency < 4000) { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeLow); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeHigh); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeLow); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeHigh); } else { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope1); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope2); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope1); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope2); } } else { /* * If temp compensation is not enabled, * set all registers to 0. */ - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, 0); } } else { REG_RMW_FIELD(ah, AR_PHY_TPC_19, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 09facba1dc6..8927fc34d84 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah, if (IS_CHAN_A_FAST_CLOCK(ah, chan)) rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - if (IS_CHAN_QUARTER_RATE(chan)) - rfMode |= AR_PHY_MODE_QUARTER; - if (IS_CHAN_HALF_RATE(chan)) - rfMode |= AR_PHY_MODE_HALF; if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF)) REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index f76139bbb74..2c42ff05efa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -592,7 +592,7 @@ static const u32 ar9331_1p1_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009fc0, 0x803e4788}, diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h index 0ac8be96097..2154efcd390 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h @@ -231,7 +231,7 @@ static const u32 ar9331_1p2_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009fc0, 0x803e4788}, diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index a01f0edb651..b995ffe88b3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -318,7 +318,7 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, @@ -348,9 +348,9 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x210d0401}, - {0x0000a3a0, 0xab9a7144}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, {0x0000a3a4, 0x00000000}, {0x0000a3a8, 0xaaaaaaaa}, {0x0000a3ac, 0x3c466478}, diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 3c9113d9b1b..8e5c3b9786e 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -257,9 +257,9 @@ static const u32 qca953x_1p0_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x1f020503}, - {0x0000a39c, 0x29180c03}, - {0x0000a3a0, 0x9a8b6844}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, {0x0000a3a4, 0x000000ff}, {0x0000a3a8, 0x6a6a6a6a}, {0x0000a3ac, 0x6a6a6a6a}, diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index e6aec2c0207..a5ca65240af 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -90,7 +90,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b5ac32cfbeb..2ca8f7e0617 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,14 +23,13 @@ #include <linux/leds.h> #include <linux/completion.h> -#include "debug.h" #include "common.h" +#include "debug.h" #include "mci.h" #include "dfs.h" #include "spectral.h" struct ath_node; -struct ath_rate_table; extern struct ieee80211_ops ath9k_ops; extern int ath9k_modparam_nohwcrypt; @@ -115,6 +114,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_TXFIFO_DEPTH 8 #define ATH_TX_ERROR 0x01 +/* Stop tx traffic 1ms before the GO goes away */ +#define ATH_P2P_PS_STOP_TIME 1000 + #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 #define IEEE80211_WEP_IVLEN 3 @@ -150,6 +152,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e)) #define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf)) +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, +}; + struct ath_txq { int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ u32 axq_qnum; /* ath9k hardware queue number */ @@ -247,7 +254,6 @@ struct ath_atx_tid { s8 bar_index; bool sched; - bool paused; bool active; }; @@ -268,6 +274,7 @@ struct ath_node { #ifdef CONFIG_ATH9K_STATION_STATISTICS struct ath_rx_rate_stats rx_rate_stats; #endif + u8 key_idx[4]; }; struct ath_tx_control { @@ -363,11 +370,15 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, /********/ struct ath_vif { + struct ieee80211_vif *vif; struct ath_node mcast_node; int av_bslot; bool primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ struct ath_buf *av_bcbuf; + + /* P2P Client */ + struct ieee80211_noa_data noa; }; struct ath9k_vif_iter_data { @@ -399,21 +410,10 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, #define ATH_BCBUF 8 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -struct ath_beacon_config { - int beacon_interval; - u16 listen_interval; - u16 dtim_period; - u16 bmiss_timeout; - u8 dtim_count; - bool enable_beacon; - bool ibss_creator; -}; - struct ath_beacon { enum { OK, /* no change needed */ @@ -423,11 +423,9 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; - u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; - struct ath9k_tx_queue_info beacon_qi; struct ath_descdma bdma; struct ath_txq *cabq; struct list_head bbuf; @@ -442,7 +440,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_set_beacon(struct ath_softc *sc); -bool ath9k_csa_is_finished(struct ath_softc *sc); +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_csa_update(struct ath_softc *sc); /*******************/ /* Link Monitoring */ @@ -472,6 +471,8 @@ int ath_update_survey_stats(struct ath_softc *sc); void ath_update_survey_nf(struct ath_softc *sc, int channel); void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); void ath_ps_full_sleep(unsigned long data); +void ath9k_p2p_ps_timer(void *priv); +void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); /**********/ /* BTCOEX */ @@ -693,15 +694,6 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define MAX_GTT_CNT 5 -enum sc_op_flags { - SC_OP_INVALID, - SC_OP_BEACONS, - SC_OP_ANI_RUN, - SC_OP_PRIM_STA_VIF, - SC_OP_HW_RESET, - SC_OP_SCANNING, -}; - /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) #define PS_WAIT_FOR_CAB BIT(1) @@ -731,7 +723,9 @@ struct ath_softc { struct completion paprd_complete; wait_queue_head_t tx_wait; - unsigned long sc_flags; + struct ath_gen_timer *p2p_ps_timer; + struct ath_vif *p2p_ps_vif; + unsigned long driver_data; u8 gtt_cnt; @@ -748,7 +742,6 @@ struct ath_softc { struct ath_rx rx; struct ath_tx tx; struct ath_beacon beacon; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_MAC80211_LEDS bool led_registered; @@ -757,7 +750,6 @@ struct ath_softc { #endif struct ath9k_hw_cal_data caldata; - int last_rssi; #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; @@ -774,11 +766,11 @@ struct ath_softc { #endif struct ath_descdma txsdma; - struct ieee80211_vif *csa_vif; struct ath_ant_comb ant_comb; u8 ant_tx, ant_rx; struct dfs_pattern_detector *dfs_detector; + u64 dfs_prev_pulse_ts; u32 wow_enabled; /* relay(fs) channel for spectral scan */ struct rchan *rfs_chan_spec_scan; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 2e8bba0eb36..e387f0b2954 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, u8 chainmask = ah->txchainmask; u8 rate = 0; - sband = &sc->sbands[common->hw->conf.chandef.chan->band]; + sband = &common->sbands[common->hw->conf.chandef.chan->band]; rate = sband->bitrates[rateidx].hw_value; if (vif->bss_conf.use_short_preamble) rate |= sband->bitrates[rateidx].hw_value_short; @@ -292,11 +292,8 @@ static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) (unsigned long long)tsfadjust, avp->av_bslot); } -bool ath9k_csa_is_finished(struct ath_softc *sc) +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ieee80211_vif *vif; - - vif = sc->csa_vif; if (!vif || !vif->csa_active) return false; @@ -304,11 +301,22 @@ bool ath9k_csa_is_finished(struct ath_softc *sc) return false; ieee80211_csa_finish(vif); - - sc->csa_vif = NULL; return true; } +static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = data; + ath9k_csa_is_finished(sc, vif); +} + +void ath9k_csa_update(struct ath_softc *sc) +{ + ieee80211_iterate_active_interfaces_atomic(sc->hw, + IEEE80211_IFACE_ITER_NORMAL, + ath9k_csa_update_vif, sc); +} + void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -319,7 +327,7 @@ void ath9k_beacon_tasklet(unsigned long data) bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int slot; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { ath_dbg(common, RESET, "reset work is pending, skip beaconing now\n"); return; @@ -362,13 +370,13 @@ void ath9k_beacon_tasklet(unsigned long data) return; } - /* EDMA devices check that in the tx completion function. */ - if (!edma && ath9k_csa_is_finished(sc)) - return; - slot = ath9k_beacon_choose_slot(sc); vif = sc->beacon.bslot[slot]; + /* EDMA devices check that in the tx completion function. */ + if (!edma && ath9k_csa_is_finished(sc, vif)) + return; + if (!vif || !vif->bss_conf.enable_beacon) return; @@ -438,33 +446,6 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, ath9k_hw_enable_interrupts(ah); } -/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ -static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) -{ - u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; - - tsf_mod = tsf & (BIT(10) - 1); - tsf_hi = tsf >> 32; - tsf_lo = ((u32) tsf) >> 10; - - mod_hi = tsf_hi % div_tu; - mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; - - return (mod_lo << 10) | tsf_mod; -} - -static u32 ath9k_get_next_tbtt(struct ath_softc *sc, u64 tsf, - unsigned int interval) -{ - struct ath_hw *ah = sc->sc_ah; - unsigned int offset; - - tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); - offset = ath9k_mod_tsf64_tu(tsf, interval); - - return (u32) tsf + TU_TO_USEC(interval) - offset; -} - /* * For multi-bss ap support beacons are either staggered evenly over N slots or * burst together. For the former arrange for the SWBA to be delivered for each @@ -474,115 +455,18 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 nexttbtt, intval; - - /* NB: the beacon interval is kept internally in TU's */ - intval = TU_TO_USEC(conf->beacon_interval); - intval /= ATH_BCBUF; - nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah), - conf->beacon_interval); - - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - - ath_dbg(common, BEACON, - "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); - ath9k_beacon_init(sc, nexttbtt, intval, false); + ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false); } -/* - * This sets up the beacon timers according to the timestamp of the last - * received beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware will wakeup in - * time to receive beacons, and configures the beacon miss handling so - * we'll receive a BMISS interrupt when we stop seeing beacons from the AP - * we've associated with. - */ -static void ath9k_beacon_config_sta(struct ath_softc *sc, +static void ath9k_beacon_config_sta(struct ath_hw *ah, struct ath_beacon_config *conf) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; - int dtim_intval, sleepduration; - u32 nexttbtt = 0, intval; - u64 tsf; - /* No need to configure beacon if we are not associated */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ath_dbg(common, BEACON, - "STA is not yet associated..skipping beacon config\n"); + if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM) return; - } - - memset(&bs, 0, sizeof(bs)); - intval = conf->beacon_interval; - - /* - * Setup dtim parameters according to - * last beacon we received (which may be none). - */ - dtim_intval = intval * conf->dtim_period; - sleepduration = conf->listen_interval * intval; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim state for the result. - */ - tsf = ath9k_hw_gettsf64(ah); - nexttbtt = ath9k_get_next_tbtt(sc, tsf, intval); - - bs.bs_intval = TU_TO_USEC(intval); - bs.bs_dtimperiod = conf->dtim_period * bs.bs_intval; - bs.bs_nexttbtt = nexttbtt; - bs.bs_nextdtim = nexttbtt; - if (conf->dtim_period > 1) - bs.bs_nextdtim = ath9k_get_next_tbtt(sc, tsf, dtim_intval); - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = conf->listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure a multiple of the beacon period is used. Also, if the sleep - * duration is greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - - bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - sleepduration)); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration); - - /* Set the computed STA beacon timers */ ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); @@ -597,36 +481,19 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 intval, nexttbtt; ath9k_reset_beacon_status(sc); - intval = TU_TO_USEC(conf->beacon_interval); - - if (conf->ibss_creator) - nexttbtt = intval; - else - nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah), - conf->beacon_interval); + ath9k_cmn_beacon_config_adhoc(ah, conf); - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - - ath_dbg(common, BEACON, - "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); - - ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator); /* * Set the global 'beacon has been configured' flag for the * joiner case in IBSS mode. */ if (!conf->ibss_creator && conf->enable_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); } static bool ath9k_allow_beacon_config(struct ath_softc *sc, @@ -646,7 +513,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { if ((vif->type == NL80211_IFTYPE_STATION) && - test_bit(SC_OP_BEACONS, &sc->sc_flags) && + test_bit(ATH_OP_BEACONS, &common->op_flags) && !avp->primary_sta_vif) { ath_dbg(common, CONFIG, "Beacon already configured for a station interface\n"); @@ -668,11 +535,8 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->dtim_period = bss_conf->dtim_period; - cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; cur_conf->ibss_creator = bss_conf->ibss_creator; - cur_conf->bmiss_timeout = - ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; /* * It looks like mac80211 may end up using beacon interval of zero in @@ -683,6 +547,9 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, if (cur_conf->beacon_interval == 0) cur_conf->beacon_interval = 100; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + /* * We don't parse dtim period from mac80211 during the driver * initialization as it breaks association with hidden-ssid @@ -698,6 +565,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; bool skip_beacon = false; @@ -710,7 +579,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { ath9k_cache_beacon_config(sc, bss_conf); ath9k_set_beacon(sc); - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); return; } @@ -749,13 +618,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, } /* - * Do not set the SC_OP_BEACONS flag for IBSS joiner mode + * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode * here, it is done in ath9k_beacon_config_adhoc(). */ if (cur_conf->enable_beacon && !skip_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); else - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + clear_bit(ATH_OP_BEACONS, &common->op_flags); } } @@ -773,7 +642,7 @@ void ath9k_set_beacon(struct ath_softc *sc) ath9k_beacon_config_adhoc(sc, cur_conf); break; case NL80211_IFTYPE_STATION: - ath9k_beacon_config_sta(sc, cur_conf); + ath9k_beacon_config_sta(sc->sc_ah, cur_conf); break; default: ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c new file mode 100644 index 00000000000..775d1d20ce0 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications 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 "common.h" + +#define FUDGE 2 + +/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */ +static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu) +{ + u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo; + + tsf_mod = tsf & (BIT(10) - 1); + tsf_hi = tsf >> 32; + tsf_lo = ((u32) tsf) >> 10; + + mod_hi = tsf_hi % div_tu; + mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu; + + return (mod_lo << 10) | tsf_mod; +} + +static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf, + unsigned int interval) +{ + unsigned int offset; + + tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); + offset = ath9k_mod_tsf64_tu(tsf, interval); + + return (u32) tsf + TU_TO_USEC(interval) - offset; +} + +/* + * This sets up the beacon timers according to the timestamp of the last + * received beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware will wakeup in + * time to receive beacons, and configures the beacon miss handling so + * we'll receive a BMISS interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs) +{ + struct ath_common *common = ath9k_hw_common(ah); + int dtim_intval; + u64 tsf; + + /* No need to configure beacon if we are not associated */ + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, BEACON, + "STA is not yet associated..skipping beacon config\n"); + return -EPERM; + } + + memset(bs, 0, sizeof(*bs)); + conf->intval = conf->beacon_interval; + + /* + * Setup dtim parameters according to + * last beacon we received (which may be none). + */ + dtim_intval = conf->intval * conf->dtim_period; + + /* + * Pull nexttbtt forward to reflect the current + * TSF and calculate dtim state for the result. + */ + tsf = ath9k_hw_gettsf64(ah); + conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval); + + bs->bs_intval = TU_TO_USEC(conf->intval); + bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval; + bs->bs_nexttbtt = conf->nexttbtt; + bs->bs_nextdtim = conf->nexttbtt; + if (conf->dtim_period > 1) + bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval); + + /* + * Calculate the number of consecutive beacons to miss* before taking + * a BMISS interrupt. The configuration is specified in TU so we only + * need calculate based on the beacon interval. Note that we clamp the + * result to at most 15 beacons. + */ + bs->bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, conf->intval); + if (bs->bs_bmissthreshold > 15) + bs->bs_bmissthreshold = 15; + else if (bs->bs_bmissthreshold <= 0) + bs->bs_bmissthreshold = 1; + + /* + * Calculate sleep duration. The configuration is given in ms. + * We ensure a multiple of the beacon period is used. Also, if the sleep + * duration is greater than the DTIM period then it makes senses + * to make it a multiple of that. + * + * XXX fixed at 100ms + */ + + bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), + conf->intval)); + if (bs->bs_sleepduration > bs->bs_dtimperiod) + bs->bs_sleepduration = bs->bs_dtimperiod; + + /* TSF out of range threshold fixed at 1 second */ + bs->bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + + ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", + bs->bs_bmissthreshold, bs->bs_sleepduration); + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta); + +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + conf->intval = TU_TO_USEC(conf->beacon_interval); + + if (conf->ibss_creator) + conf->nexttbtt = conf->intval; + else + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc); + +/* + * For multi-bss ap support beacons are either staggered evenly over N slots or + * burst together. For the former arrange for the SWBA to be delivered for each + * slot. Slots that are not occupied will generate nothing. + */ +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* NB: the beacon interval is kept internally in TU's */ + conf->intval = TU_TO_USEC(conf->beacon_interval); + conf->intval /= bc_buf; + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_ap); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h new file mode 100644 index 00000000000..3665d27f0dc --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications 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. + */ + +struct ath_beacon_config; + +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs); +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf); +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf); diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c new file mode 100644 index 00000000000..3b289f93340 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-debug.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications 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 "common.h" + +static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_hw *ah = file->private_data; + u32 len = 0, size = 6000; + char *buf; + size_t retval; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_modal_eeprom = { + .read = read_file_modal_eeprom, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + + +void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah) +{ + debugfs_create_file("modal_eeprom", S_IRUSR, debugfs_phy, ah, + &fops_modal_eeprom); +} +EXPORT_SYMBOL(ath9k_cmn_debug_modal_eeprom); + +static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_hw *ah = file->private_data; + u32 len = 0, size = 1500; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_base_eeprom = { + .read = read_file_base_eeprom, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah) +{ + debugfs_create_file("base_eeprom", S_IRUSR, debugfs_phy, ah, + &fops_base_eeprom); +} +EXPORT_SYMBOL(ath9k_cmn_debug_base_eeprom); + +void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, + struct ath_rx_status *rs) +{ +#define RX_PHY_ERR_INC(c) rxstats->phy_err_stats[c]++ +#define RX_CMN_STAT_INC(c) (rxstats->c++) + + RX_CMN_STAT_INC(rx_pkts_all); + rxstats->rx_bytes_all += rs->rs_datalen; + + if (rs->rs_status & ATH9K_RXERR_CRC) + RX_CMN_STAT_INC(crc_err); + if (rs->rs_status & ATH9K_RXERR_DECRYPT) + RX_CMN_STAT_INC(decrypt_crc_err); + if (rs->rs_status & ATH9K_RXERR_MIC) + RX_CMN_STAT_INC(mic_err); + if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) + RX_CMN_STAT_INC(pre_delim_crc_err); + if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) + RX_CMN_STAT_INC(post_delim_crc_err); + if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) + RX_CMN_STAT_INC(decrypt_busy_err); + + if (rs->rs_status & ATH9K_RXERR_PHY) { + RX_CMN_STAT_INC(phy_err); + if (rs->rs_phyerr < ATH9K_PHYERR_MAX) + RX_PHY_ERR_INC(rs->rs_phyerr); + } + +#undef RX_CMN_STAT_INC +#undef RX_PHY_ERR_INC +} +EXPORT_SYMBOL(ath9k_cmn_debug_stat_rx); + +static ssize_t read_file_recv(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define RXS_ERR(s, e) \ + do { \ + len += scnprintf(buf + len, size - len, \ + "%18s : %10u\n", s, \ + rxstats->e); \ + } while (0) + + struct ath_rx_stats *rxstats = file->private_data; + char *buf; + unsigned int len = 0, size = 1600; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + RXS_ERR("PKTS-ALL", rx_pkts_all); + RXS_ERR("BYTES-ALL", rx_bytes_all); + RXS_ERR("BEACONS", rx_beacons); + RXS_ERR("FRAGS", rx_frags); + RXS_ERR("SPECTRAL", rx_spectral); + + RXS_ERR("CRC ERR", crc_err); + RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); + RXS_ERR("PHY ERR", phy_err); + RXS_ERR("MIC ERR", mic_err); + RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err); + RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err); + RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err); + RXS_ERR("LENGTH-ERR", rx_len_err); + RXS_ERR("OOM-ERR", rx_oom_err); + RXS_ERR("RATE-ERR", rx_rate_err); + RXS_ERR("TOO-MANY-FRAGS", rx_too_many_frags_err); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef RXS_ERR +} + +static const struct file_operations fops_recv = { + .read = read_file_recv, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats) +{ + debugfs_create_file("recv", S_IRUSR, debugfs_phy, rxstats, + &fops_recv); +} +EXPORT_SYMBOL(ath9k_cmn_debug_recv); + +static ssize_t read_file_phy_err(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PHY_ERR(s, p) \ + len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \ + rxstats->phy_err_stats[p]); + + struct ath_rx_stats *rxstats = file->private_data; + char *buf; + unsigned int len = 0, size = 1600; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); + PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); + PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); + PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); + PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); + PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); + PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); + PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); + PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); + PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); + PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); + PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); + PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); + PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); + PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); + PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); + PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); + PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); + PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); + PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); + PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); + PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); + PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); + PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PHY_ERR +} + +static const struct file_operations fops_phy_err = { + .read = read_file_phy_err, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats) +{ + debugfs_create_file("phy_err", S_IRUSR, debugfs_phy, rxstats, + &fops_phy_err); +} +EXPORT_SYMBOL(ath9k_cmn_debug_phy_err); diff --git a/drivers/net/wireless/ath/ath9k/common-debug.h b/drivers/net/wireless/ath/ath9k/common-debug.h new file mode 100644 index 00000000000..7c9788490f7 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-debug.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications 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. + */ + + + +/** + * struct ath_rx_stats - RX Statistics + * @rx_pkts_all: No. of total frames received, including ones that + may have had errors. + * @rx_bytes_all: No. of total bytes received, including ones that + may have had errors. + * @crc_err: No. of frames with incorrect CRC value + * @decrypt_crc_err: No. of frames whose CRC check failed after + decryption process completed + * @phy_err: No. of frames whose reception failed because the PHY + encountered an error + * @mic_err: No. of frames with incorrect TKIP MIC verification failure + * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections + * @post_delim_crc_err: Post-Frame delimiter CRC error detections + * @decrypt_busy_err: Decryption interruptions counter + * @phy_err_stats: Individual PHY error statistics + * @rx_len_err: No. of frames discarded due to bad length. + * @rx_oom_err: No. of frames dropped due to OOM issues. + * @rx_rate_err: No. of frames dropped due to rate errors. + * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. + * @rx_beacons: No. of beacons received. + * @rx_frags: No. of rx-fragements received. + * @rx_spectral: No of spectral packets received. + */ +struct ath_rx_stats { + u32 rx_pkts_all; + u32 rx_bytes_all; + u32 crc_err; + u32 decrypt_crc_err; + u32 phy_err; + u32 mic_err; + u32 pre_delim_crc_err; + u32 post_delim_crc_err; + u32 decrypt_busy_err; + u32 phy_err_stats[ATH9K_PHYERR_MAX]; + u32 rx_len_err; + u32 rx_oom_err; + u32 rx_rate_err; + u32 rx_too_many_frags_err; + u32 rx_beacons; + u32 rx_frags; + u32 rx_spectral; +}; + +void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah); +void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah); +void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, + struct ath_rx_status *rs); +void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats); +void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats); diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c new file mode 100644 index 00000000000..a006c149972 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications 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. + */ + +/* We use the hw_value as an index into our private channel structure */ + +#include "common.h" + +#define CHAN2G(_freq, _idx) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; + +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), +}; + +int ath9k_cmn_init_channels_rates(struct ath_common *common) +{ + struct ath_hw *ah = (struct ath_hw *)common->ah; + void *channels; + + BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + + ARRAY_SIZE(ath9k_5ghz_chantable) != + ATH9K_NUM_CHANNELS); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_2ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_2ghz_chantable, + sizeof(ath9k_2ghz_chantable)); + common->sbands[IEEE80211_BAND_2GHZ].channels = channels; + common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + common->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + common->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } + + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_5ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_5ghz_chantable, + sizeof(ath9k_5ghz_chantable)); + common->sbands[IEEE80211_BAND_5GHZ].channels = channels; + common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + common->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + common->sbands[IEEE80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + common->sbands[IEEE80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; + } + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_init_channels_rates); + +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 tx_streams, rx_streams; + int i, max_streams; + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + + if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + max_streams = 1; + else if (AR_SREV_9462(ah)) + max_streams = 2; + else if (AR_SREV_9300_20_OR_LATER(ah)) + max_streams = 3; + else + max_streams = 2; + + if (AR_SREV_9280_20_OR_LATER(ah)) { + if (max_streams >= 2) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + } + + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); + rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); + + ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + + if (tx_streams != rx_streams) { + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } + + for (i = 0; i < rx_streams; i++) + ht_info->mcs.rx_mask[i] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} +EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap); + +void ath9k_cmn_reload_chainmask(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT)) + return; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); +} +EXPORT_SYMBOL(ath9k_cmn_reload_chainmask); diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h new file mode 100644 index 00000000000..ac03fca5ffd --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications 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. + */ + +int ath9k_cmn_init_channels_rates(struct ath_common *common); +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info); +void ath9k_cmn_reload_chainmask(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 768c733cad3..c6dd7f1fed6 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -27,6 +27,250 @@ MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards."); MODULE_LICENSE("Dual BSD/GPL"); +/* Assumes you've already done the endian to CPU conversion */ +bool ath9k_cmn_rx_accept(struct ath_common *common, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error, + unsigned int rxfilter) +{ + struct ath_hw *ah = common->ah; + bool is_mc, is_valid_tkip, strip_mic, mic_error; + __le16 fc; + + fc = hdr->frame_control; + + is_mc = !!is_multicast_ether_addr(hdr->addr1); + is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && + test_bit(rx_stats->rs_keyix, common->tkip_keymap); + strip_mic = is_valid_tkip && ieee80211_is_data(fc) && + ieee80211_has_protected(fc) && + !(rx_stats->rs_status & + (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | + ATH9K_RXERR_KEYMISS)); + + /* + * Key miss events are only relevant for pairwise keys where the + * descriptor does contain a valid key index. This has been observed + * mostly with CCMP encryption. + */ + if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || + !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) + rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; + + mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && + !ieee80211_has_morefrags(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && + (rx_stats->rs_status & ATH9K_RXERR_MIC); + + /* + * The rx_stats->rs_status will not be set until the end of the + * chained descriptors so it can be ignored if rs_more is set. The + * rs_more will be false at the last element of the chained + * descriptors. + */ + if (rx_stats->rs_status != 0) { + u8 status_mask; + + if (rx_stats->rs_status & ATH9K_RXERR_CRC) { + rxs->flag |= RX_FLAG_FAILED_FCS_CRC; + mic_error = false; + } + + if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || + (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { + *decrypt_error = true; + mic_error = false; + } + + + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_KEYMISS; + + if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL)) + status_mask |= ATH9K_RXERR_CRC; + + if (rx_stats->rs_status & ~status_mask) + return false; + } + + /* + * For unicast frames the MIC error bit can have false positives, + * so all MIC error reports need to be validated in software. + * False negatives are not common, so skip software verification + * if the hardware considers the MIC valid. + */ + if (strip_mic) + rxs->flag |= RX_FLAG_MMIC_STRIPPED; + else if (is_mc && mic_error) + rxs->flag |= RX_FLAG_MMIC_ERROR; + + return true; +} +EXPORT_SYMBOL(ath9k_cmn_rx_accept); + +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_hdr *hdr; + int hdrlen, padpos, padsize; + u8 keyix; + __le16 fc; + + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + padpos = ieee80211_hdrlen(fc); + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - padpos % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = padpos & 3; + if (padsize && skb->len>=padpos+padsize+FCS_LEN) { + memmove(skb->data + padsize, skb->data, padpos); + skb_pull(skb, padsize); + } + + keyix = rx_stats->rs_keyix; + + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && + ieee80211_has_protected(fc)) { + rxs->flag |= RX_FLAG_DECRYPTED; + } else if (ieee80211_has_protected(fc) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, common->keymap)) + rxs->flag |= RX_FLAG_DECRYPTED; + } + if (ah->sw_mgmt_crypto && + (rxs->flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(fc)) + /* Use software decrypt for management frames. */ + rxs->flag &= ~RX_FLAG_DECRYPTED; +} +EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); + +int ath9k_cmn_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs) +{ + struct ieee80211_supported_band *sband; + enum ieee80211_band band; + unsigned int i = 0; + struct ath_hw *ah = common->ah; + + band = ah->curchan->chan->band; + sband = hw->wiphy->bands[band]; + + if (IS_CHAN_QUARTER_RATE(ah->curchan)) + rxs->flag |= RX_FLAG_5MHZ; + else if (IS_CHAN_HALF_RATE(ah->curchan)) + rxs->flag |= RX_FLAG_10MHZ; + + if (rx_stats->rs_rate & 0x80) { + /* HT rate */ + rxs->flag |= RX_FLAG_HT; + rxs->flag |= rx_stats->flag; + rxs->rate_idx = rx_stats->rs_rate & 0x7f; + return 0; + } + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { + rxs->rate_idx = i; + return 0; + } + if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { + rxs->flag |= RX_FLAG_SHORTPRE; + rxs->rate_idx = i; + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(ath9k_cmn_process_rate); + +void ath9k_cmn_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs) +{ + struct ath_hw *ah = common->ah; + int last_rssi; + int rssi = rx_stats->rs_rssi; + int i, j; + + /* + * RSSI is not available for subframes in an A-MPDU. + */ + if (rx_stats->rs_moreaggr) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; + return; + } + + /* + * Check if the RSSI for the last subframe in an A-MPDU + * or an unaggregated frame is valid. + */ + if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; + return; + } + + for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { + s8 rssi; + + if (!(ah->rxchainmask & BIT(i))) + continue; + + rssi = rx_stats->rs_rssi_ctl[i]; + if (rssi != ATH9K_RSSI_BAD) { + rxs->chains |= BIT(j); + rxs->chain_signal[j] = ah->noise + rssi; + } + j++; + } + + /* + * Update Beacon RSSI, this is used by ANI. + */ + if (rx_stats->is_mybeacon && + ((ah->opmode == NL80211_IFTYPE_STATION) || + (ah->opmode == NL80211_IFTYPE_ADHOC))) { + ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi); + last_rssi = common->last_rssi; + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + if (rssi < 0) + rssi = 0; + + ah->stats.avgbrssi = rssi; + } + + rxs->signal = ah->noise + rx_stats->rs_rssi; +} +EXPORT_SYMBOL(ath9k_cmn_process_rssi); + int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index eb85e1bdca8..ffc454b1863 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -21,6 +21,10 @@ #include "hw.h" #include "hw-ops.h" +#include "common-init.h" +#include "common-beacon.h" +#include "common-debug.h" + /* Common header for Atheros 802.11n base driver cores */ #define WME_BA_BMP_SIZE 64 @@ -42,6 +46,38 @@ #define ATH_EP_RND(x, mul) \ (((x) + ((mul)/2)) / (mul)) +#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) + +struct ath_beacon_config { + int beacon_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; + bool enable_beacon; + bool ibss_creator; + u32 nexttbtt; + u32 intval; +}; + +bool ath9k_cmn_rx_accept(struct ath_common *common, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error, + unsigned int rxfilter); +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error); +int ath9k_cmn_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs); +void ath9k_cmn_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index ab7264c1d8f..6cc42be48d4 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -135,46 +135,45 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; char *buf; + int i; + struct { + const char *name; + unsigned int val; + } ani_info[] = { + { "ANI RESET", ah->stats.ast_ani_reset }, + { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel }, + { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel }, + { "SPUR UP", ah->stats.ast_ani_spurup }, + { "SPUR DOWN", ah->stats.ast_ani_spurup }, + { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon }, + { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff }, + { "MRC-CCK ON", ah->stats.ast_ani_ccklow }, + { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh }, + { "FIR-STEP UP", ah->stats.ast_ani_stepup }, + { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown }, + { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero }, + { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs }, + { "CCK ERRORS", ah->stats.ast_ani_cckerrs }, + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - if (common->disable_ani) { - len += scnprintf(buf + len, size - len, "%s: %s\n", - "ANI", "DISABLED"); + len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI", + common->disable_ani ? "DISABLED" : "ENABLED"); + + if (common->disable_ani) goto exit; - } - len += scnprintf(buf + len, size - len, "%15s: %s\n", - "ANI", "ENABLED"); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "ANI RESET", ah->stats.ast_ani_reset); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "SPUR UP", ah->stats.ast_ani_spurup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "SPUR DOWN", ah->stats.ast_ani_spurup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK ON", ah->stats.ast_ani_ccklow); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK OFF", ah->stats.ast_ani_cckhigh); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP UP", ah->stats.ast_ani_stepup); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP DOWN", ah->stats.ast_ani_stepdown); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs); - len += scnprintf(buf + len, size - len, "%15s: %u\n", - "CCK ERRORS", ah->stats.ast_ani_cckerrs); + for (i = 0; i < ARRAY_SIZE(ani_info); i++) + len += scnprintf(buf + len, size - len, "%15s: %u\n", + ani_info[i].name, ani_info[i].val); + exit: if (len > size) len = size; @@ -209,7 +208,7 @@ static ssize_t write_file_ani(struct file *file, common->disable_ani = !ani; if (common->disable_ani) { - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } else { ath_check_ani(sc); @@ -307,13 +306,13 @@ static ssize_t read_file_antenna_diversity(struct file *file, struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; struct ath_hw_antcomb_conf div_ant_conf; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; char *buf; - char *lna_conf_str[4] = {"LNA1_MINUS_LNA2", - "LNA2", - "LNA1", - "LNA1_PLUS_LNA2"}; + static const char *lna_conf_str[4] = { + "LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2" + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -716,10 +715,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; struct ath_txq *txq; char *buf; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; int i; - char *qname[4] = {"VO", "VI", "BE", "BK"}; + static const char *qname[4] = { + "VO", "VI", "BE", "BK" + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -866,6 +868,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf, "%17s: %2d\n", "PLL RX Hang", sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); len += scnprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "MAC Hang", + sc->debug.stats.reset[RESET_TYPE_MAC_HANG]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "Stuck Beacon", + sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]); + len += scnprintf(buf + len, sizeof(buf) - len, "%17s: %2d\n", "MCI Reset", sc->debug.stats.reset[RESET_TYPE_MCI]); @@ -940,151 +948,11 @@ static const struct file_operations fops_reset = { .llseek = default_llseek, }; -static ssize_t read_file_recv(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define RXS_ERR(s, e) \ - do { \ - len += scnprintf(buf + len, size - len, \ - "%18s : %10u\n", s, \ - sc->debug.stats.rxstats.e);\ - } while (0) - - struct ath_softc *sc = file->private_data; - char *buf; - unsigned int len = 0, size = 1600; - ssize_t retval = 0; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - RXS_ERR("PKTS-ALL", rx_pkts_all); - RXS_ERR("BYTES-ALL", rx_bytes_all); - RXS_ERR("BEACONS", rx_beacons); - RXS_ERR("FRAGS", rx_frags); - RXS_ERR("SPECTRAL", rx_spectral); - - RXS_ERR("CRC ERR", crc_err); - RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); - RXS_ERR("PHY ERR", phy_err); - RXS_ERR("MIC ERR", mic_err); - RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err); - RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err); - RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err); - RXS_ERR("LENGTH-ERR", rx_len_err); - RXS_ERR("OOM-ERR", rx_oom_err); - RXS_ERR("RATE-ERR", rx_rate_err); - RXS_ERR("TOO-MANY-FRAGS", rx_too_many_frags_err); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef RXS_ERR -} - void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { -#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ - - RX_STAT_INC(rx_pkts_all); - sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; - - if (rs->rs_status & ATH9K_RXERR_CRC) - RX_STAT_INC(crc_err); - if (rs->rs_status & ATH9K_RXERR_DECRYPT) - RX_STAT_INC(decrypt_crc_err); - if (rs->rs_status & ATH9K_RXERR_MIC) - RX_STAT_INC(mic_err); - if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) - RX_STAT_INC(pre_delim_crc_err); - if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) - RX_STAT_INC(post_delim_crc_err); - if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) - RX_STAT_INC(decrypt_busy_err); - - if (rs->rs_status & ATH9K_RXERR_PHY) { - RX_STAT_INC(phy_err); - if (rs->rs_phyerr < ATH9K_PHYERR_MAX) - RX_PHY_ERR_INC(rs->rs_phyerr); - } - -#undef RX_PHY_ERR_INC -} - -static const struct file_operations fops_recv = { - .read = read_file_recv, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_phy_err(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PHY_ERR(s, p) \ - len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \ - sc->debug.stats.rxstats.phy_err_stats[p]); - - struct ath_softc *sc = file->private_data; - char *buf; - unsigned int len = 0, size = 1600; - ssize_t retval = 0; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); - PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); - PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); - PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); - PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); - PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); - PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); - PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); - PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); - PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); - PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); - PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); - PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); - PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); - PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); - PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); - PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); - PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); - PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); - PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); - PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); - PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); - PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); - PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); - PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); - PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PHY_ERR + ath9k_cmn_debug_stat_rx(&sc->debug.stats.rxstats, rs); } -static const struct file_operations fops_phy_err = { - .read = read_file_phy_err, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - static ssize_t read_file_regidx(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1260,62 +1128,6 @@ static const struct file_operations fops_dump_nfcal = { .llseek = default_llseek, }; -static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - u32 len = 0, size = 1500; - ssize_t retval = 0; - char *buf; - - buf = kzalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size); - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; -} - -static const struct file_operations fops_base_eeprom = { - .read = read_file_base_eeprom, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - u32 len = 0, size = 6000; - char *buf; - size_t retval; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size); - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; -} - -static const struct file_operations fops_modal_eeprom = { - .read = read_file_modal_eeprom, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1516,10 +1328,10 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_misc); debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_reset); - debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_recv); - debugfs_create_file("phy_err", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_phy_err); + + ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); + ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); + debugfs_create_u8("rx_chainmask", S_IRUSR, sc->debug.debugfs_phy, &ah->rxchainmask); debugfs_create_u8("tx_chainmask", S_IRUSR, sc->debug.debugfs_phy, @@ -1539,10 +1351,10 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_regdump); debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dump_nfcal); - debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_base_eeprom); - debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_modal_eeprom); + + ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index cc7a025d833..53ae15bd0c9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -18,7 +18,6 @@ #define DEBUG_H #include "hw.h" -#include "rc.h" #include "dfs_debug.h" struct ath_txq; @@ -222,50 +221,6 @@ struct ath_rx_rate_stats { } cck_stats[4]; }; -/** - * struct ath_rx_stats - RX Statistics - * @rx_pkts_all: No. of total frames received, including ones that - may have had errors. - * @rx_bytes_all: No. of total bytes received, including ones that - may have had errors. - * @crc_err: No. of frames with incorrect CRC value - * @decrypt_crc_err: No. of frames whose CRC check failed after - decryption process completed - * @phy_err: No. of frames whose reception failed because the PHY - encountered an error - * @mic_err: No. of frames with incorrect TKIP MIC verification failure - * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections - * @post_delim_crc_err: Post-Frame delimiter CRC error detections - * @decrypt_busy_err: Decryption interruptions counter - * @phy_err_stats: Individual PHY error statistics - * @rx_len_err: No. of frames discarded due to bad length. - * @rx_oom_err: No. of frames dropped due to OOM issues. - * @rx_rate_err: No. of frames dropped due to rate errors. - * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. - * @rx_beacons: No. of beacons received. - * @rx_frags: No. of rx-fragements received. - * @rx_spectral: No of spectral packets received. - */ -struct ath_rx_stats { - u32 rx_pkts_all; - u32 rx_bytes_all; - u32 crc_err; - u32 decrypt_crc_err; - u32 phy_err; - u32 mic_err; - u32 pre_delim_crc_err; - u32 post_delim_crc_err; - u32 decrypt_busy_err; - u32 phy_err_stats[ATH9K_PHYERR_MAX]; - u32 rx_len_err; - u32 rx_oom_err; - u32 rx_rate_err; - u32 rx_too_many_frags_err; - u32 rx_beacons; - u32 rx_frags; - u32 rx_spectral; -}; - #define ANT_MAIN 0 #define ANT_ALT 1 diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c index d76e6e0120d..ffca918ff16 100644 --- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -72,7 +72,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, ath_txq_lock(sc, txq); if (tid->active) { len += scnprintf(buf + len, size - len, - "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n", + "%3d%11d%10d%10d%10d%10d%9d%6d\n", tid->tidno, tid->seq_start, tid->seq_next, @@ -80,8 +80,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, tid->baw_head, tid->baw_tail, tid->bar_index, - tid->sched, - tid->paused); + tid->sched); } ath_txq_unlock(sc, txq); } diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 857bb28b389..726271c7c33 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -178,12 +178,12 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, pe.ts = mactime; if (ath9k_postprocess_radar_event(sc, &ard, &pe)) { struct dfs_pattern_detector *pd = sc->dfs_detector; - static u64 last_ts; ath_dbg(common, DFS, "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, " "width=%d, rssi=%d, delta_ts=%llu\n", - pe.freq, pe.ts, pe.width, pe.rssi, pe.ts-last_ts); - last_ts = pe.ts; + pe.freq, pe.ts, pe.width, pe.rssi, + pe.ts - sc->dfs_prev_pulse_ts); + sc->dfs_prev_pulse_ts = pe.ts; DFS_STAT_INC(sc, pulses_processed); if (pd != NULL && pd->add_pulse(pd, &pe)) { DFS_STAT_INC(sc, radar_detected); diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h index 0a7ddf4c88c..7936c9126a2 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.h +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h @@ -21,6 +21,8 @@ #include "hw.h" +struct ath_softc; + /** * struct ath_dfs_stats - DFS Statistics per wiphy * @pulses_total: pulses reported by HW diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 6d5d716adc1..8e7153b186e 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -54,6 +54,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { .driver_info = AR9280_USB }, /* SMC Networks */ { USB_DEVICE(0x0411, 0x017f), .driver_info = AR9280_USB }, /* Sony UWA-BR100 */ + { USB_DEVICE(0x0411, 0x0197), + .driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */ { USB_DEVICE(0x04da, 0x3904), .driver_info = AR9280_USB }, diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 99a203174f4..09a5d72f3ff 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -39,7 +39,6 @@ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define TSF_TO_TU(_h, _l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) @@ -277,7 +276,6 @@ struct ath9k_htc_rxbuf { }; struct ath9k_htc_rx { - int last_rssi; /* FIXME: per-STA */ struct list_head rxbuf; spinlock_t rxbuflock; }; @@ -327,14 +325,14 @@ static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) #define TX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c += a) -#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) -#define RX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c += a) +#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c++) +#define RX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.skbrx_stats.c += a) #define CAB_STAT_INC priv->debug.tx_stats.cab_queued++ #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, - struct ath_htc_rx_status *rxs); + struct ath_rx_status *rs); struct ath_tx_stats { u32 buf_queued; @@ -347,25 +345,18 @@ struct ath_tx_stats { u32 queue_stats[IEEE80211_NUM_ACS]; }; -struct ath_rx_stats { +struct ath_skbrx_stats { u32 skb_allocated; u32 skb_completed; u32 skb_completed_bytes; u32 skb_dropped; - u32 err_crc; - u32 err_decrypt_crc; - u32 err_mic; - u32 err_pre_delim; - u32 err_post_delim; - u32 err_decrypt_busy; - u32 err_phy; - u32 err_phy_stats[ATH9K_PHYERR_MAX]; }; struct ath9k_debug { struct dentry *debugfs_phy; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; + struct ath_skbrx_stats skbrx_stats; }; void ath9k_htc_get_et_strings(struct ieee80211_hw *hw, @@ -387,7 +378,7 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, #define TX_QSTAT_INC(c) do { } while (0) static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, - struct ath_htc_rx_status *rxs) + struct ath_rx_status *rs) { } @@ -407,12 +398,18 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define DEFAULT_SWBA_RESPONSE 40 /* in TUs */ #define MIN_SWBA_RESPONSE 10 /* in TUs */ -struct htc_beacon_config { +struct htc_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; - u16 beacon_interval; - u16 dtim_period; - u16 bmiss_timeout; - u32 bmiss_cnt; + u32 bmisscnt; + u32 beaconq; + int slottime; + int slotupdate; }; struct ath_btcoex { @@ -440,12 +437,8 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#define OP_INVALID BIT(0) -#define OP_SCANNING BIT(1) -#define OP_ENABLE_BEACON BIT(2) #define OP_BT_PRIORITY_DETECTED BIT(3) #define OP_BT_SCAN BIT(4) -#define OP_ANI_RUNNING BIT(5) #define OP_TSF_RESET BIT(6) struct ath9k_htc_priv { @@ -488,10 +481,10 @@ struct ath9k_htc_priv { unsigned long op_flags; struct ath9k_hw_cal_data caldata; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; spinlock_t beacon_lock; - struct htc_beacon_config cur_beacon_conf; + struct ath_beacon_config cur_beacon_conf; + struct htc_beacon beacon; struct ath9k_htc_rx rx; struct ath9k_htc_tx tx; @@ -516,7 +509,6 @@ struct ath9k_htc_priv { struct work_struct led_work; #endif - int beaconq; int cabq; int hwq_map[IEEE80211_NUM_ACS]; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8b575773459..e8b6ec3c1db 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -26,7 +26,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); - ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); + ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi); if (priv->ah->opmode == NL80211_IFTYPE_AP || priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) { @@ -54,220 +54,78 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } - if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { + if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) { ath_err(ath9k_hw_common(ah), - "Unable to update beacon queue %u!\n", priv->beaconq); + "Unable to update beacon queue %u!\n", priv->beacon.beaconq); } else { - ath9k_hw_resettxqueue(ah, priv->beaconq); + ath9k_hw_resettxqueue(ah, priv->beacon.beaconq); } } - -static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +/* + * Both nexttbtt and intval have to be in usecs. + */ +static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf, + bool reset_tsf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ath9k_beacon_state bs; - enum ath9k_int imask = 0; - int dtimperiod, dtimcount, sleepduration; - int bmiss_timeout; - u32 nexttbtt = 0, intval, tsftu; - __be32 htc_imask = 0; - u64 tsf; - int num_beacons, offset, dtim_dec_count; + struct ath_hw *ah = priv->ah; int ret __attribute__ ((unused)); + __be32 htc_imask = 0; u8 cmd_rsp; - memset(&bs, 0, sizeof(bs)); - - intval = bss_conf->beacon_interval; - bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); - - /* - * Setup dtim parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = bss_conf->dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ - dtimperiod = 1; - dtimcount = 1; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; - - sleepduration = intval; - if (sleepduration <= 0) - sleepduration = intval; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim state for the result. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - - num_beacons = tsftu / intval + 1; - offset = tsftu % intval; - nexttbtt = tsftu - offset; - if (offset) - nexttbtt += intval; - - /* DTIM Beacon every dtimperiod Beacon */ - dtim_dec_count = num_beacons % dtimperiod; - dtimcount -= dtim_dec_count; - if (dtimcount < 0) - dtimcount += dtimperiod; - - bs.bs_intval = TU_TO_USEC(intval); - bs.bs_nexttbtt = TU_TO_USEC(nexttbtt); - bs.bs_dtimperiod = dtimperiod * bs.bs_intval; - bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount * bs.bs_intval; - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure a multiple of the beacon period is used. Also, if the sleep - * duration is greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - - bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - sleepduration)); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n", - intval, tsf, tsftu); - ath_dbg(common, CONFIG, "bmiss: %u sleep: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration); - - /* Set the computed STA beacon timers */ + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); - imask |= ATH9K_INT_BMISS; - htc_imask = cpu_to_be32(imask); + if (reset_tsf) + ath9k_hw_reset_tsf(ah); + ath9k_htc_beaconq_config(priv); + ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval); + priv->beacon.bmisscnt = 0; + htc_imask = cpu_to_be32(ah->imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } -static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, + struct ath_beacon_config *bss_conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_beacon_state bs; enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; int ret __attribute__ ((unused)); u8 cmd_rsp; - u64 tsf; - intval = bss_conf->beacon_interval; - intval /= ATH9K_HTC_MAX_BCN_VIF; - nexttbtt = intval; - - /* - * To reduce beacon misses under heavy TX load, - * set the beacon response time to a larger value. - */ - if (intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - - if (test_bit(OP_TSF_RESET, &priv->op_flags)) { - ath9k_hw_reset_tsf(priv->ah); - clear_bit(OP_TSF_RESET, &priv->op_flags); - } else { - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - } - - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) - imask |= ATH9K_INT_SWBA; - - ath_dbg(common, CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); - - ath9k_htc_beaconq_config(priv); + if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM) + return; WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; + ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); + imask |= ATH9K_INT_BMISS; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } -static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; - __be32 htc_imask = 0; - int ret __attribute__ ((unused)); - u8 cmd_rsp; - u64 tsf; - - intval = bss_conf->beacon_interval; - nexttbtt = intval; - - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - - /* - * Only one IBSS interfce is allowed. - */ - if (intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + struct ath_hw *ah = priv->ah; + ah->imask = 0; - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) - imask |= ATH9K_INT_SWBA; + ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); + ath9k_htc_beacon_init(priv, conf, false); +} - ath_dbg(common, CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); +static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf) +{ + struct ath_hw *ah = priv->ah; + ah->imask = 0; - WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; - htc_imask = cpu_to_be32(imask); - WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + ath9k_cmn_beacon_config_adhoc(ah, conf); + ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); } void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, @@ -287,7 +145,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; skb = ieee80211_get_buffered_bc(priv->hw, vif); @@ -348,10 +206,10 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; avp = (struct ath9k_htc_vif *)vif->drv_priv; - if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) { + if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) { spin_unlock_bh(&priv->beacon_lock); return; } @@ -431,8 +289,8 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, int slot; if (swba->beacon_pending != 0) { - priv->cur_beacon_conf.bmiss_cnt++; - if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { + priv->beacon.bmisscnt++; + if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) { ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n"); ieee80211_queue_work(priv->hw, &priv->fatal_work); @@ -440,16 +298,16 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, return; } - if (priv->cur_beacon_conf.bmiss_cnt) { + if (priv->beacon.bmisscnt) { ath_dbg(common, BSTUCK, "Resuming beacon xmit after %u misses\n", - priv->cur_beacon_conf.bmiss_cnt); - priv->cur_beacon_conf.bmiss_cnt = 0; + priv->beacon.bmisscnt); + priv->beacon.bmisscnt = 0; } slot = ath9k_htc_choose_bslot(priv, swba); spin_lock_bh(&priv->beacon_lock); - if (priv->cur_beacon_conf.bslot[slot] == NULL) { + if (priv->beacon.bslot[slot] == NULL) { spin_unlock_bh(&priv->beacon_lock); return; } @@ -468,13 +326,13 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { - if (priv->cur_beacon_conf.bslot[i] == NULL) { + if (priv->beacon.bslot[i] == NULL) { avp->bslot = i; break; } } - priv->cur_beacon_conf.bslot[avp->bslot] = vif; + priv->beacon.bslot[avp->bslot] = vif; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", @@ -488,7 +346,7 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; spin_lock_bh(&priv->beacon_lock); - priv->cur_beacon_conf.bslot[avp->bslot] = NULL; + priv->beacon.bslot[avp->bslot] = NULL; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", @@ -504,7 +362,7 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; u64 tsfadjust; if (avp->bslot == 0) @@ -536,7 +394,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; bool beacon_configured; @@ -591,7 +449,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; @@ -627,7 +485,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; switch (priv->ah->opmode) { case NL80211_IFTYPE_STATION: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index fb071ee4fcf..8b529e4b8ac 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -243,39 +243,14 @@ static const struct file_operations fops_xmit = { }; void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, - struct ath_htc_rx_status *rxs) + struct ath_rx_status *rs) { -#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++ - - if (rxs->rs_status & ATH9K_RXERR_CRC) - priv->debug.rx_stats.err_crc++; - if (rxs->rs_status & ATH9K_RXERR_DECRYPT) - priv->debug.rx_stats.err_decrypt_crc++; - if (rxs->rs_status & ATH9K_RXERR_MIC) - priv->debug.rx_stats.err_mic++; - if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE) - priv->debug.rx_stats.err_pre_delim++; - if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST) - priv->debug.rx_stats.err_post_delim++; - if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY) - priv->debug.rx_stats.err_decrypt_busy++; - - if (rxs->rs_status & ATH9K_RXERR_PHY) { - priv->debug.rx_stats.err_phy++; - if (rxs->rs_phyerr < ATH9K_PHYERR_MAX) - RX_PHY_ERR_INC(rxs->rs_phyerr); - } - -#undef RX_PHY_ERR_INC + ath9k_cmn_debug_stat_rx(&priv->debug.rx_stats, rs); } -static ssize_t read_file_recv(struct file *file, char __user *user_buf, +static ssize_t read_file_skb_rx(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { -#define PHY_ERR(s, p) \ - len += scnprintf(buf + len, size - len, "%20s : %10u\n", s, \ - priv->debug.rx_stats.err_phy_stats[p]); - struct ath9k_htc_priv *priv = file->private_data; char *buf; unsigned int len = 0, size = 1500; @@ -287,63 +262,13 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, len += scnprintf(buf + len, size - len, "%20s : %10u\n", "SKBs allocated", - priv->debug.rx_stats.skb_allocated); + priv->debug.skbrx_stats.skb_allocated); len += scnprintf(buf + len, size - len, "%20s : %10u\n", "SKBs completed", - priv->debug.rx_stats.skb_completed); + priv->debug.skbrx_stats.skb_completed); len += scnprintf(buf + len, size - len, "%20s : %10u\n", "SKBs Dropped", - priv->debug.rx_stats.skb_dropped); - - len += scnprintf(buf + len, size - len, - "%20s : %10u\n", "CRC ERR", - priv->debug.rx_stats.err_crc); - len += scnprintf(buf + len, size - len, - "%20s : %10u\n", "DECRYPT CRC ERR", - priv->debug.rx_stats.err_decrypt_crc); - len += scnprintf(buf + len, size - len, - "%20s : %10u\n", "MIC ERR", - priv->debug.rx_stats.err_mic); - len += scnprintf(buf + len, size - len, - "%20s : %10u\n", "PRE-DELIM CRC ERR", - priv->debug.rx_stats.err_pre_delim); - len += scnprintf(buf + len, size - len, - "%20s : %10u\n", "POST-DELIM CRC ERR", - priv->debug.rx_stats.err_post_delim); - len += scnprintf(buf + len, size - len, - "%20s : %10u\n", "DECRYPT BUSY ERR", - priv->debug.rx_stats.err_decrypt_busy); - len += scnprintf(buf + len, size - len, - "%20s : %10u\n", "TOTAL PHY ERR", - priv->debug.rx_stats.err_phy); - - - PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); - PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); - PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); - PHY_ERR("RATE", ATH9K_PHYERR_RATE); - PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); - PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); - PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); - PHY_ERR("TOR", ATH9K_PHYERR_TOR); - PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); - PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); - PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); - PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); - PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); - PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); - PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); - PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); - PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); - PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); - PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); - PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); - PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); - PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); - PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); - PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); - PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); - PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); + priv->debug.skbrx_stats.skb_dropped); if (len > size) len = size; @@ -352,12 +277,10 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, kfree(buf); return retval; - -#undef PHY_ERR } -static const struct file_operations fops_recv = { - .read = read_file_recv, +static const struct file_operations fops_skb_rx = { + .read = read_file_skb_rx, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -486,423 +409,6 @@ static const struct file_operations fops_debug = { .llseek = default_llseek, }; -static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - struct ath_common *common = ath9k_hw_common(priv->ah); - struct base_eep_header *pBase = NULL; - unsigned int len = 0, size = 1500; - ssize_t retval = 0; - char *buf; - - pBase = ath9k_htc_get_eeprom_base(priv); - - if (pBase == NULL) { - ath_err(common, "Unknown EEPROM type\n"); - return 0; - } - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", "Major Version", - pBase->version >> 12); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", "Minor Version", - pBase->version & 0xFFF); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", "Checksum", - pBase->checksum); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", "Length", - pBase->length); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", "RegDomain1", - pBase->regDmn[0]); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", "RegDomain2", - pBase->regDmn[1]); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "TX Mask", pBase->txMask); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "RX Mask", pBase->rxMask); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Allow 5GHz", - !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Allow 2GHz", - !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 2GHz HT20", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20)); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 2GHz HT40", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40)); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 5Ghz HT20", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20)); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 5Ghz HT40", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Big Endian", - !!(pBase->eepMisc & 0x01)); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Cal Bin Major Ver", - (pBase->binBuildNumber >> 24) & 0xFF); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Cal Bin Minor Ver", - (pBase->binBuildNumber >> 16) & 0xFF); - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "Cal Bin Build", - (pBase->binBuildNumber >> 8) & 0xFF); - - /* - * UB91 specific data. - */ - if (AR_SREV_9271(priv->ah)) { - struct base_eep_header_4k *pBase4k = - &priv->ah->eeprom.map4k.baseEepHeader; - - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "TX Gain type", - pBase4k->txGainType); - } - - /* - * UB95 specific data. - */ - if (priv->ah->hw_version.usbdev == AR9287_USB) { - struct base_eep_ar9287_header *pBase9287 = - &priv->ah->eeprom.map9287.baseEepHeader; - - len += scnprintf(buf + len, size - len, - "%20s : %10ddB\n", - "Power Table Offset", - pBase9287->pwrTableOffset); - - len += scnprintf(buf + len, size - len, - "%20s : %10d\n", - "OpenLoop Power Ctrl", - pBase9287->openLoopPwrCntl); - } - - len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", - pBase->macAddr); - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; -} - -static const struct file_operations fops_base_eeprom = { - .read = read_file_base_eeprom, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_4k_modal_eeprom(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val) \ - do { \ - len += scnprintf(buf + len, size - len, "%20s : %10d\n",\ - _s, (_val)); \ - } while (0) - - struct ath9k_htc_priv *priv = file->private_data; - struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader; - unsigned int len = 0, size = 2048; - ssize_t retval = 0; - char *buf; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); - PR_EEP("Ant. Common Control", pModal->antCtrlCommon); - PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); - PR_EEP("Switch Settle", pModal->switchSettling); - PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); - PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); - PR_EEP("ADC Desired size", pModal->adcDesiredSize); - PR_EEP("PGA Desired size", pModal->pgaDesiredSize); - PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); - PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); - PR_EEP("txEndToRxOn", pModal->txEndToRxOn); - PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); - PR_EEP("CCA Threshold)", pModal->thresh62); - PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); - PR_EEP("xpdGain", pModal->xpdGain); - PR_EEP("External PD", pModal->xpd); - PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); - PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); - PR_EEP("pdGainOverlap", pModal->pdGainOverlap); - PR_EEP("O/D Bias Version", pModal->version); - PR_EEP("CCK OutputBias", pModal->ob_0); - PR_EEP("BPSK OutputBias", pModal->ob_1); - PR_EEP("QPSK OutputBias", pModal->ob_2); - PR_EEP("16QAM OutputBias", pModal->ob_3); - PR_EEP("64QAM OutputBias", pModal->ob_4); - PR_EEP("CCK Driver1_Bias", pModal->db1_0); - PR_EEP("BPSK Driver1_Bias", pModal->db1_1); - PR_EEP("QPSK Driver1_Bias", pModal->db1_2); - PR_EEP("16QAM Driver1_Bias", pModal->db1_3); - PR_EEP("64QAM Driver1_Bias", pModal->db1_4); - PR_EEP("CCK Driver2_Bias", pModal->db2_0); - PR_EEP("BPSK Driver2_Bias", pModal->db2_1); - PR_EEP("QPSK Driver2_Bias", pModal->db2_2); - PR_EEP("16QAM Driver2_Bias", pModal->db2_3); - PR_EEP("64QAM Driver2_Bias", pModal->db2_4); - PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); - PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); - PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); - PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); - PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); - PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); - PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); - PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); - PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); - PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1); - PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2); - PR_EEP("TX Diversity", pModal->tx_diversity); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PR_EEP -} - -static ssize_t read_def_modal_eeprom(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val) \ - do { \ - if (pBase->opCapFlags & AR5416_OPFLAGS_11G) { \ - pModal = &priv->ah->eeprom.def.modalHeader[1]; \ - len += scnprintf(buf + len, size - len, "%20s : %8d%7s", \ - _s, (_val), "|"); \ - } \ - if (pBase->opCapFlags & AR5416_OPFLAGS_11A) { \ - pModal = &priv->ah->eeprom.def.modalHeader[0]; \ - len += scnprintf(buf + len, size - len, "%9d\n",\ - (_val)); \ - } \ - } while (0) - - struct ath9k_htc_priv *priv = file->private_data; - struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader; - struct modal_eep_header *pModal = NULL; - unsigned int len = 0, size = 3500; - ssize_t retval = 0; - char *buf; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += scnprintf(buf + len, size - len, - "%31s %15s\n", "2G", "5G"); - len += scnprintf(buf + len, size - len, - "%32s %16s\n", "====", "====\n"); - - PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); - PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); - PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]); - PR_EEP("Ant. Common Control", pModal->antCtrlCommon); - PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); - PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); - PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]); - PR_EEP("Switch Settle", pModal->switchSettling); - PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); - PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); - PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]); - PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); - PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); - PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]); - PR_EEP("ADC Desired size", pModal->adcDesiredSize); - PR_EEP("PGA Desired size", pModal->pgaDesiredSize); - PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); - PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]); - PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]); - PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); - PR_EEP("txEndToRxOn", pModal->txEndToRxOn); - PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); - PR_EEP("CCA Threshold)", pModal->thresh62); - PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); - PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); - PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]); - PR_EEP("xpdGain", pModal->xpdGain); - PR_EEP("External PD", pModal->xpd); - PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); - PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); - PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]); - PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); - PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); - PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]); - PR_EEP("pdGainOverlap", pModal->pdGainOverlap); - PR_EEP("Chain0 OutputBias", pModal->ob); - PR_EEP("Chain0 DriverBias", pModal->db); - PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); - PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain); - PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain); - PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); - PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); - PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); - PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); - PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); - PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]); - PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); - PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); - PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]); - PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); - PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); - PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]); - PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]); - PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); - PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]); - PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]); - PR_EEP("Chain1 OutputBias", pModal->ob_ch1); - PR_EEP("Chain1 DriverBias", pModal->db_ch1); - PR_EEP("LNA Control", pModal->lna_ctl); - PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]); - PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]); - PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PR_EEP -} - -static ssize_t read_9287_modal_eeprom(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val) \ - do { \ - len += scnprintf(buf + len, size - len, "%20s : %10d\n",\ - _s, (_val)); \ - } while (0) - - struct ath9k_htc_priv *priv = file->private_data; - struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader; - unsigned int len = 0, size = 3000; - ssize_t retval = 0; - char *buf; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); - PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); - PR_EEP("Ant. Common Control", pModal->antCtrlCommon); - PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); - PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); - PR_EEP("Switch Settle", pModal->switchSettling); - PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); - PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); - PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); - PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); - PR_EEP("ADC Desired size", pModal->adcDesiredSize); - PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); - PR_EEP("txEndToRxOn", pModal->txEndToRxOn); - PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); - PR_EEP("CCA Threshold)", pModal->thresh62); - PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); - PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); - PR_EEP("xpdGain", pModal->xpdGain); - PR_EEP("External PD", pModal->xpd); - PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); - PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); - PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); - PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); - PR_EEP("pdGainOverlap", pModal->pdGainOverlap); - PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); - PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); - PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); - PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); - PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); - PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); - PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); - PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); - PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); - PR_EEP("AR92x7 Version", pModal->version); - PR_EEP("DriverBias1", pModal->db1); - PR_EEP("DriverBias2", pModal->db1); - PR_EEP("CCK OutputBias", pModal->ob_cck); - PR_EEP("PSK OutputBias", pModal->ob_psk); - PR_EEP("QAM OutputBias", pModal->ob_qam); - PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PR_EEP -} - -static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - - if (AR_SREV_9271(priv->ah)) - return read_4k_modal_eeprom(file, user_buf, count, ppos); - else if (priv->ah->hw_version.usbdev == AR9280_USB) - return read_def_modal_eeprom(file, user_buf, count, ppos); - else if (priv->ah->hw_version.usbdev == AR9287_USB) - return read_9287_modal_eeprom(file, user_buf, count, ppos); - - return 0; -} - -static const struct file_operations fops_modal_eeprom = { - .read = read_file_modal_eeprom, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - - /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = { @@ -947,6 +453,8 @@ int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw, #define STXBASE priv->debug.tx_stats #define SRXBASE priv->debug.rx_stats +#define SKBTXBASE priv->debug.tx_stats +#define SKBRXBASE priv->debug.skbrx_stats #define ASTXQ(a) \ data[i++] = STXBASE.a[IEEE80211_AC_BE]; \ data[i++] = STXBASE.a[IEEE80211_AC_BK]; \ @@ -960,24 +468,24 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, struct ath9k_htc_priv *priv = hw->priv; int i = 0; - data[i++] = STXBASE.skb_success; - data[i++] = STXBASE.skb_success_bytes; - data[i++] = SRXBASE.skb_completed; - data[i++] = SRXBASE.skb_completed_bytes; + data[i++] = SKBTXBASE.skb_success; + data[i++] = SKBTXBASE.skb_success_bytes; + data[i++] = SKBRXBASE.skb_completed; + data[i++] = SKBRXBASE.skb_completed_bytes; ASTXQ(queue_stats); - data[i++] = SRXBASE.err_crc; - data[i++] = SRXBASE.err_decrypt_crc; - data[i++] = SRXBASE.err_phy; - data[i++] = SRXBASE.err_mic; - data[i++] = SRXBASE.err_pre_delim; - data[i++] = SRXBASE.err_post_delim; - data[i++] = SRXBASE.err_decrypt_busy; + data[i++] = SRXBASE.crc_err; + data[i++] = SRXBASE.decrypt_crc_err; + data[i++] = SRXBASE.phy_err; + data[i++] = SRXBASE.mic_err; + data[i++] = SRXBASE.pre_delim_crc_err; + data[i++] = SRXBASE.post_delim_crc_err; + data[i++] = SRXBASE.decrypt_busy_err; - data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_RADAR]; - data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_OFDM_TIMING]; - data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_CCK_TIMING]; + data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_RADAR]; + data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]; + data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_CCK_TIMING]; WARN_ON(i != ATH9K_HTC_SSTATS_LEN); } @@ -1001,18 +509,21 @@ int ath9k_htc_init_debug(struct ath_hw *ah) priv, &fops_tgt_rx_stats); debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, priv, &fops_xmit); - debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_recv); + debugfs_create_file("skb_rx", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_skb_rx); + + ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); + ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats); + debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, priv, &fops_slot); debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, priv, &fops_queue); debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, priv, &fops_debug); - debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_base_eeprom); - debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_modal_eeprom); + + ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); + ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index c57d6b859c0..8a3bd5fe3a5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -38,93 +38,6 @@ static int ath9k_ps_enable; module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -#define CHAN2G(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -static struct ieee80211_channel ath9k_2ghz_channels[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -static struct ieee80211_channel ath9k_5ghz_channels[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), -}; - #ifdef CONFIG_MAC80211_LEDS static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, @@ -343,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, } } +static void ath9k_regwrite_multi(struct ath_common *common) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + u32 rsp_status; + int r; + + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, + (u8 *) &priv->wmi->multi_write, + sizeof(struct register_write) * priv->wmi->multi_write_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_dbg(common, WMI, + "REGISTER WRITE FAILED, multi len: %d\n", + priv->wmi->multi_write_idx); + } + priv->wmi->multi_write_idx = 0; +} + static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; @@ -369,8 +301,6 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; mutex_lock(&priv->wmi->multi_write_mutex); @@ -383,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) priv->wmi->multi_write_idx++; /* If the buffer is full, send it out. */ - if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, - (u8 *) &rsp_status, sizeof(rsp_status), - 100); - if (unlikely(r)) { - ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); - } - priv->wmi->multi_write_idx = 0; - } + if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) + ath9k_regwrite_multi(common); mutex_unlock(&priv->wmi->multi_write_mutex); } @@ -426,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv) struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; atomic_dec(&priv->wmi->mwrite_cnt); mutex_lock(&priv->wmi->multi_write_mutex); - if (priv->wmi->multi_write_idx) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, - (u8 *) &rsp_status, sizeof(rsp_status), - 100); - if (unlikely(r)) { - ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); - } - priv->wmi->multi_write_idx = 0; - } + if (priv->wmi->multi_write_idx) + ath9k_regwrite_multi(common); mutex_unlock(&priv->wmi->multi_write_mutex); } @@ -491,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = { .eeprom_read = ath_usb_eeprom_read, }; -static void setup_ht_cap(struct ath9k_htc_priv *priv, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_common *common = ath9k_hw_common(priv->ah); - u8 tx_streams, rx_streams; - int i; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - - /* ath9k_htc supports only 1 or 2 stream devices */ - tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); - rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static int ath9k_init_queues(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); @@ -544,8 +405,8 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv) for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) priv->hwq_map[i] = -1; - priv->beaconq = ath9k_hw_beaconq_setup(priv->ah); - if (priv->beaconq == -1) { + priv->beacon.beaconq = ath9k_hw_beaconq_setup(priv->ah); + if (priv->beacon.beaconq == -1) { ath_err(common, "Unable to setup BEACON xmit queue\n"); goto err; } @@ -580,37 +441,13 @@ err: return -EINVAL; } -static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) -{ - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - priv->sbands[IEEE80211_BAND_2GHZ].channels = - ath9k_2ghz_channels; - priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - priv->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_channels); - priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; - priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - priv->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_channels); - priv->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } -} - static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + common->last_rssi = ATH_RSSI_DUMMY_MARKER; priv->ah->opmode = NL80211_IFTYPE_STATION; } @@ -622,12 +459,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, struct ath_common *common; int i, ret = 0, csz = 0; - set_bit(OP_INVALID, &priv->op_flags); - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) return -ENOMEM; + ah->dev = priv->dev; ah->hw_version.devid = devid; ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; @@ -647,6 +483,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, common->priv = priv; common->debug_mask = ath9k_debug; common->btcoex_enabled = ath9k_htc_btcoex_enable == 1; + set_bit(ATH_OP_INVALID, &common->op_flags); spin_lock_init(&priv->beacon_lock); spin_lock_init(&priv->tx.tx_lock); @@ -682,10 +519,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, goto err_queues; for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) - priv->cur_beacon_conf.bslot[i] = NULL; + priv->beacon.bslot[i] = NULL; + priv->beacon.slottime = ATH9K_SLOT_TIME_9; + ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); - ath9k_init_channels_rates(priv); ath9k_init_misc(priv); ath9k_htc_init_btcoex(priv, product); @@ -721,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = { static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw) { + struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(priv->ah); struct base_eep_header *pBase; @@ -765,19 +604,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->sbands[IEEE80211_BAND_2GHZ]; + &common->sbands[IEEE80211_BAND_2GHZ]; if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->sbands[IEEE80211_BAND_5GHZ]; - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } + &common->sbands[IEEE80211_BAND_5GHZ]; + + ath9k_cmn_reload_chainmask(ah); pBase = ath9k_htc_get_eeprom_base(priv); if (pBase) { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index c9254a61ca5..5627917c5ff 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -95,8 +95,10 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) if ((vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT) && - bss_conf->enable_beacon) + bss_conf->enable_beacon) { priv->reconfig_beacon = true; + priv->rearm_ani = true; + } if (bss_conf->assoc) { priv->rearm_ani = true; @@ -250,13 +252,14 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, u8 cmd_rsp; int ret; - if (test_bit(OP_INVALID, &priv->op_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); ath9k_htc_ps_wakeup(priv); + ath9k_htc_stop_ani(priv); del_timer_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); @@ -304,7 +307,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, htc_start(priv->htc); - if (!test_bit(OP_SCANNING, &priv->op_flags) && + if (!test_bit(ATH_OP_SCANNING, &common->op_flags) && !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); @@ -748,7 +751,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) common->ani.shortcal_timer = timestamp; common->ani.checkani_timer = timestamp; - set_bit(OP_ANI_RUNNING, &priv->op_flags); + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -756,8 +759,9 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); cancel_delayed_work_sync(&priv->ani_work); - clear_bit(OP_ANI_RUNNING, &priv->op_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); } void ath9k_htc_ani_work(struct work_struct *work) @@ -942,7 +946,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath_dbg(common, CONFIG, "Failed to update capability in target\n"); - clear_bit(OP_INVALID, &priv->op_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); htc_start(priv->htc); spin_lock_bh(&priv->tx.tx_lock); @@ -971,7 +975,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&priv->mutex); return; @@ -1013,7 +1017,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) ath9k_htc_ps_restore(priv); ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); - set_bit(OP_INVALID, &priv->op_flags); + set_bit(ATH_OP_INVALID, &common->op_flags); ath_dbg(common, CONFIG, "Driver halt\n"); mutex_unlock(&priv->mutex); @@ -1087,7 +1091,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && - !test_bit(OP_ANI_RUNNING, &priv->op_flags)) { + !test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { ath9k_hw_set_tsfadjust(priv->ah, true); ath9k_htc_start_ani(priv); } @@ -1245,13 +1249,14 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); u32 rfilt; mutex_lock(&priv->mutex); changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(ath9k_hw_common(priv->ah), ANY, "Unable to configure filter on invalid state\n"); mutex_unlock(&priv->mutex); @@ -1474,7 +1479,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) { common->curaid = bss_conf->aid; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); } } @@ -1496,6 +1503,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); + int slottime; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); @@ -1507,6 +1515,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, bss_conf->assoc ? priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; + if (!bss_conf->assoc) + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + if (priv->ah->opmode == NL80211_IFTYPE_STATION) { ath9k_htc_choose_set_bssid(priv); if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) @@ -1528,7 +1539,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n", bss_conf->bssid); ath9k_htc_set_tsfadjust(priv, vif); - set_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 1; ath9k_htc_beacon_config(priv, vif); } @@ -1542,7 +1553,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon disabled for BSS: %pM\n", bss_conf->bssid); - clear_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 0; ath9k_htc_beacon_config(priv, vif); } } @@ -1568,11 +1579,21 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) - ah->slottime = 9; + slottime = 9; else - ah->slottime = 20; - - ath9k_hw_init_global_settings(ah); + slottime = 20; + if (vif->type == NL80211_IFTYPE_AP) { + /* + * Defer update, so that connected stations can adjust + * their settings at the same time. + * See beacon.c for more details + */ + priv->beacon.slottime = slottime; + priv->beacon.updateslot = UPDATE; + } else { + ah->slottime = slottime; + ath9k_hw_init_global_settings(ah); + } } if (changed & BSS_CHANGED_HT) @@ -1669,10 +1690,11 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - set_bit(OP_SCANNING, &priv->op_flags); + set_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); cancel_work_sync(&priv->ps_work); ath9k_htc_stop_ani(priv); @@ -1682,10 +1704,11 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - clear_bit(OP_SCANNING, &priv->op_flags); + clear_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); ath9k_htc_ps_wakeup(priv); ath9k_htc_vif_reconfig(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 12e0f32a490..bb86eb2ffc9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -471,8 +471,11 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, if (!txok || !vif || !txs) goto send_mac80211; - if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) + if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) { tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + } if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; @@ -924,46 +927,43 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) void ath9k_host_rx_init(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); ath9k_hw_rxena(priv->ah); ath9k_htc_opmode_init(priv); - ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags)); - priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; + ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags)); } -static void ath9k_process_rate(struct ieee80211_hw *hw, - struct ieee80211_rx_status *rxs, - u8 rx_rate, u8 rs_flags) +static inline void convert_htc_flag(struct ath_rx_status *rx_stats, + struct ath_htc_rx_status *rxstatus) { - struct ieee80211_supported_band *sband; - enum ieee80211_band band; - unsigned int i = 0; - - if (rx_rate & 0x80) { - /* HT rate */ - rxs->flag |= RX_FLAG_HT; - if (rs_flags & ATH9K_RX_2040) - rxs->flag |= RX_FLAG_40MHZ; - if (rs_flags & ATH9K_RX_GI) - rxs->flag |= RX_FLAG_SHORT_GI; - rxs->rate_idx = rx_rate & 0x7f; - return; - } - - band = hw->conf.chandef.chan->band; - sband = hw->wiphy->bands[band]; - - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_rate) { - rxs->rate_idx = i; - return; - } - if (sband->bitrates[i].hw_value_short == rx_rate) { - rxs->rate_idx = i; - rxs->flag |= RX_FLAG_SHORTPRE; - return; - } - } + rx_stats->flag = 0; + if (rxstatus->rs_flags & ATH9K_RX_2040) + rx_stats->flag |= RX_FLAG_40MHZ; + if (rxstatus->rs_flags & ATH9K_RX_GI) + rx_stats->flag |= RX_FLAG_SHORT_GI; +} +static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, + struct ath_htc_rx_status *rxstatus) +{ + rx_stats->rs_datalen = rxstatus->rs_datalen; + rx_stats->rs_status = rxstatus->rs_status; + rx_stats->rs_phyerr = rxstatus->rs_phyerr; + rx_stats->rs_rssi = rxstatus->rs_rssi; + rx_stats->rs_keyix = rxstatus->rs_keyix; + rx_stats->rs_rate = rxstatus->rs_rate; + rx_stats->rs_antenna = rxstatus->rs_antenna; + rx_stats->rs_more = rxstatus->rs_more; + + memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl, + sizeof(rx_stats->rs_rssi_ctl)); + memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext, + sizeof(rx_stats->rs_rssi_ext)); + + rx_stats->rs_isaggr = rxstatus->rs_isaggr; + rx_stats->rs_moreaggr = rxstatus->rs_moreaggr; + rx_stats->rs_num_delims = rxstatus->rs_num_delims; + convert_htc_flag(rx_stats, rxstatus); } static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, @@ -975,10 +975,10 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw = priv->hw; struct sk_buff *skb = rxbuf->skb; struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath_hw *ah = common->ah; struct ath_htc_rx_status *rxstatus; - int hdrlen, padsize; - int last_rssi = ATH_RSSI_DUMMY_MARKER; - __le16 fc; + struct ath_rx_status rx_stats; + bool decrypt_error; if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", @@ -996,106 +996,41 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, goto rx_next; } - ath9k_htc_err_stat_rx(priv, rxstatus); - /* Get the RX status information */ - memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); - skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - - padsize = hdrlen & 3; - if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - if (rxbuf->rxstatus.rs_status != 0) { - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) - goto rx_next; - - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { - /* FIXME */ - } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; - else - rx_status->flag |= RX_FLAG_MMIC_ERROR; - } - - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { - if (rxbuf->rxstatus.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - goto rx_next; - } else { - if (rxbuf->rxstatus.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; - } - } - } - - if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { - u8 keyix; - keyix = rxbuf->rxstatus.rs_keyix; - if (keyix != ATH9K_RXKEYIX_INVALID) { - rx_status->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) && - skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - if (test_bit(keyix, common->keymap)) - rx_status->flag |= RX_FLAG_DECRYPTED; - } - } - - ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, - rxbuf->rxstatus.rs_flags); - - if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && - !rxbuf->rxstatus.rs_moreaggr) - ATH_RSSI_LPF(priv->rx.last_rssi, - rxbuf->rxstatus.rs_rssi); - - last_rssi = priv->rx.last_rssi; + /* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER). + * After this, we can drop this part of skb. */ + rx_status_htc_to_ath(&rx_stats, rxstatus); + ath9k_htc_err_stat_rx(priv, &rx_stats); + rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp); + skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - if (ath_is_mybeacon(common, hdr)) { - s8 rssi = rxbuf->rxstatus.rs_rssi; + /* + * everything but the rate is checked here, the rate check is done + * separately to avoid doing two lookups for a rate for each frame. + */ + hdr = (struct ieee80211_hdr *)skb->data; + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, + &decrypt_error, priv->rxfilter)) + goto rx_next; - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + ath9k_cmn_rx_skb_postprocess(common, skb, &rx_stats, + rx_status, decrypt_error); - if (rssi < 0) - rssi = 0; + if (ath9k_cmn_process_rate(common, hw, &rx_stats, rx_status)) + goto rx_next; - priv->ah->stats.avgbrssi = rssi; - } + rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr); + ath9k_cmn_process_rssi(common, hw, &rx_stats, rx_status); - rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); - rx_status->band = hw->conf.chandef.chan->band; - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; - rx_status->antenna = rxbuf->rxstatus.rs_antenna; + rx_status->band = ah->curchan->chan->band; + rx_status->freq = ah->curchan->chan->center_freq; + rx_status->antenna = rx_stats.rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; return true; - rx_next: return false; } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index aac4a406a51..a0ff5b63705 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -358,6 +358,36 @@ ret: kfree_skb(skb); } +static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle, + struct sk_buff *skb) +{ + uint32_t *pattern = (uint32_t *)skb->data; + + switch (*pattern) { + case 0x33221199: + { + struct htc_panic_bad_vaddr *htc_panic; + htc_panic = (struct htc_panic_bad_vaddr *) skb->data; + dev_err(htc_handle->dev, "ath: firmware panic! " + "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n", + htc_panic->exccause, htc_panic->pc, + htc_panic->badvaddr); + break; + } + case 0x33221299: + { + struct htc_panic_bad_epid *htc_panic; + htc_panic = (struct htc_panic_bad_epid *) skb->data; + dev_err(htc_handle->dev, "ath: firmware panic! " + "bad epid: 0x%08x\n", htc_panic->epid); + break; + } + default: + dev_err(htc_handle->dev, "ath: uknown panic pattern!\n"); + break; + } +} + /* * HTC Messages are handled directly here and the obtained SKB * is freed. @@ -379,6 +409,12 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, htc_hdr = (struct htc_frame_hdr *) skb->data; epid = htc_hdr->endpoint_id; + if (epid == 0x99) { + ath9k_htc_fw_panic_report(htc_handle, skb); + kfree_skb(skb); + return; + } + if (epid >= ENDPOINT_MAX) { if (pipe_id != USB_REG_IN_PIPE) dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index e1ffbb6bd63..06474ccc769 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -77,6 +77,18 @@ struct htc_config_pipe_msg { u8 credits; } __packed; +struct htc_panic_bad_vaddr { + __be32 pattern; + __be32 exccause; + __be32 pc; + __be32 badvaddr; +} __packed; + +struct htc_panic_bad_epid { + __be32 pattern; + __be32 epid; +} __packed; + struct htc_ep_callbacks { void *priv; void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9078a6c5a74..2a8ed8375ec 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -23,11 +23,9 @@ #include "hw.h" #include "hw-ops.h" -#include "rc.h" #include "ar9003_mac.h" #include "ar9003_mci.h" #include "ar9003_phy.h" -#include "debug.h" #include "ath9k.h" static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); @@ -247,6 +245,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) return; case AR9300_DEVID_AR953X: ah->hw_version.macVersion = AR_SREV_VERSION_9531; + if (ah->get_mac_revision) + ah->hw_version.macRev = ah->get_mac_revision(); return; } @@ -883,7 +883,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; if (AR_SREV_9300_20_OR_LATER(ah)) { @@ -3048,6 +3048,7 @@ static struct { { AR_SREV_VERSION_9462, "9462" }, { AR_SREV_VERSION_9550, "9550" }, { AR_SREV_VERSION_9565, "9565" }, + { AR_SREV_VERSION_9531, "9531" }, }; /* For devices with external radios */ diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 1fc2e5a26b5..0246b990fe8 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -61,112 +61,11 @@ static int ath9k_ps_enable; module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -bool is_ath9k_unloaded; -/* We use the hw_value as an index into our private channel structure */ - -#define CHAN2G(_freq, _idx) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_2ghz_chantable[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_5ghz_chantable[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} +static int ath9k_use_chanctx; +module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); +MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), -}; +bool is_ath9k_unloaded; #ifdef CONFIG_MAC80211_LEDS static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { @@ -258,64 +157,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl /* Initialization */ /**************************/ -static void setup_ht_cap(struct ath_softc *sc, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u8 tx_streams, rx_streams; - int i, max_streams; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) - ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) - max_streams = 1; - else if (AR_SREV_9462(ah)) - max_streams = 2; - else if (AR_SREV_9300_20_OR_LATER(ah)) - max_streams = 3; - else - max_streams = 2; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - if (max_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - } - - /* set up supported mcs set */ - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); - rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static void ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { @@ -486,51 +327,6 @@ static int ath9k_init_queues(struct ath_softc *sc) return 0; } -static int ath9k_init_channels_rates(struct ath_softc *sc) -{ - void *channels; - - BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + - ARRAY_SIZE(ath9k_5ghz_chantable) != - ATH9K_NUM_CHANNELS); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_2ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_2ghz_chantable, - sizeof(ath9k_2ghz_chantable)); - sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_5ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_5ghz_chantable, - sizeof(ath9k_5ghz_chantable)); - sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } - return 0; -} - static void ath9k_init_misc(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -538,7 +334,7 @@ static void ath9k_init_misc(struct ath_softc *sc) setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->config.txpowlimit = ATH_TXPOWER_MAX; memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); sc->beacon.slottime = ATH9K_SLOT_TIME_9; @@ -716,7 +512,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, sc->tx99_power = MAX_RATE_POWER + 1; init_waitqueue_head(&sc->tx_wait); - if (!pdata) { + if (!pdata || pdata->use_eeprom) { ah->ah_flags |= AH_USE_EEPROM; sc->sc_ah->led_pin = -1; } else { @@ -793,10 +589,13 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_btcoex; - ret = ath9k_init_channels_rates(sc); + ret = ath9k_cmn_init_channels_rates(common); if (ret) goto err_btcoex; + sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, + NULL, sc, AR_FIRST_NDP_TIMER); + ath9k_cmn_init_crypto(sc->sc_ah); ath9k_init_misc(sc); ath_fill_led_pin(sc); @@ -823,10 +622,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct cfg80211_chan_def chandef; int i; - sband = &sc->sbands[band]; + sband = &common->sbands[band]; for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; ah->curchan = &ah->channels[chan->hw_value]; @@ -849,29 +649,21 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) ah->curchan = curchan; } -void ath9k_reload_chainmask_settings(struct ath_softc *sc) -{ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)) - return; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); -} - static const struct ieee80211_iface_limit if_limits[] = { - { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_WDS) }, + { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) }, { .max = 8, .types = #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif - BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_AP) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, }; +static const struct ieee80211_iface_limit wds_limits[] = { + { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, +}; + static const struct ieee80211_iface_limit if_dfs_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH @@ -889,6 +681,14 @@ static const struct ieee80211_iface_combination if_comb[] = { .beacon_int_infra_match = true, }, { + .limits = wds_limits, + .n_limits = ARRAY_SIZE(wds_limits), + .max_interfaces = 2048, + .num_different_channels = 1, + .beacon_int_infra_match = true, + }, +#ifdef CONFIG_ATH9K_DFS_CERTIFIED + { .limits = if_dfs_limits, .n_limits = ARRAY_SIZE(if_dfs_limits), .max_interfaces = 1, @@ -897,6 +697,7 @@ static const struct ieee80211_iface_combination if_comb[] = { .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20), } +#endif }; static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) @@ -927,19 +728,23 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE); if (!config_enabled(CONFIG_ATH9K_TX99)) { hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); hw->wiphy->iface_combinations = if_comb; - hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + if (!ath9k_use_chanctx) { + hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); + } else + hw->wiphy->n_iface_combinations = 1; } hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; @@ -949,6 +754,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->queues = 4; hw->max_rates = 4; @@ -969,13 +775,13 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; + &common->sbands[IEEE80211_BAND_2GHZ]; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; + &common->sbands[IEEE80211_BAND_5GHZ]; ath9k_init_wow(hw); - ath9k_reload_chainmask_settings(sc); + ath9k_cmn_reload_chainmask(ah); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } @@ -998,6 +804,9 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, common = ath9k_hw_common(ah); ath9k_set_hw_capab(sc, hw); + /* Will be cleared in ath9k_start() */ + set_bit(ATH_OP_INVALID, &common->op_flags); + /* Initialize regulatory */ error = ath_regd_init(&common->regulatory, sc->hw->wiphy, ath9k_reg_notifier); @@ -1067,6 +876,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc) { int i = 0; + if (sc->p2p_ps_timer) + ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer); + ath9k_deinit_btcoex(sc); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) @@ -1106,19 +918,11 @@ static int __init ath9k_init(void) { int error; - /* Register rate control algorithm */ - error = ath_rate_control_register(); - if (error != 0) { - pr_err("Unable to register rate control algorithm: %d\n", - error); - goto err_out; - } - error = ath_pci_init(); if (error < 0) { pr_err("No PCI devices found, driver not installed\n"); error = -ENODEV; - goto err_rate_unregister; + goto err_out; } error = ath_ahb_init(); @@ -1131,9 +935,6 @@ static int __init ath9k_init(void) err_pci_exit: ath_pci_exit(); - - err_rate_unregister: - ath_rate_control_unregister(); err_out: return error; } @@ -1144,7 +945,6 @@ static void __exit ath9k_exit(void) is_ath9k_unloaded = true; ath_ahb_exit(); ath_pci_exit(); - ath_rate_control_unregister(); pr_info("%s: Driver unloaded\n", dev_info); } module_exit(ath9k_exit); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 30dcef5aba1..72a715fe8f2 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -115,13 +115,14 @@ void ath_hw_pll_work(struct work_struct *work) u32 pll_sqsum; struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); /* * ensure that the PLL WAR is executed only * after the STA is associated (or) if the * beaconing had started in interfaces that * uses beacons. */ - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) return; if (sc->tx99_state) @@ -414,7 +415,7 @@ void ath_start_ani(struct ath_softc *sc) unsigned long timestamp = jiffies_to_msecs(jiffies); if (common->disable_ani || - !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) || + !test_bit(ATH_OP_ANI_RUN, &common->op_flags) || (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) return; @@ -438,6 +439,7 @@ void ath_stop_ani(struct ath_softc *sc) void ath_check_ani(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; /* @@ -453,23 +455,23 @@ void ath_check_ani(struct ath_softc *sc) * Disable ANI only when there are no * associated stations. */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } } else if (ah->opmode == NL80211_IFTYPE_STATION) { - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } - if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); + if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_start_ani(sc); } return; stop_ani: - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 5f727588ca2..275205ab5f1 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -827,7 +827,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) return; } - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; async_mask = AR_INTR_MAC_IRQ; @@ -958,3 +958,25 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) return; } EXPORT_SYMBOL(ath9k_hw_set_interrupts); + +#define ATH9K_HW_MAX_DCU 10 +#define ATH9K_HW_SLICE_PER_DCU 16 +#define ATH9K_HW_BIT_IN_SLICE 16 +void ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set) +{ + int dcu_idx; + u32 filter; + + for (dcu_idx = 0; dcu_idx < 10; dcu_idx++) { + filter = SM(set, AR_D_TXBLK_WRITE_COMMAND); + filter |= SM(dcu_idx, AR_D_TXBLK_WRITE_DCU); + filter |= SM((destidx / ATH9K_HW_SLICE_PER_DCU), + AR_D_TXBLK_WRITE_SLICE); + filter |= BIT(destidx % ATH9K_HW_BIT_IN_SLICE); + ath_dbg(ath9k_hw_common(ah), PS, + "DCU%d staid %d set %d txfilter %08x\n", + dcu_idx, destidx, set, filter); + REG_WRITE(ah, AR_D_TXBLK_BASE, filter); + } +} +EXPORT_SYMBOL(ath9k_hw_set_tx_filter); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 10271373a0c..da768675753 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -155,12 +155,8 @@ struct ath_htc_rx_status { u8 rs_status; u8 rs_phyerr; int8_t rs_rssi; - int8_t rs_rssi_ctl0; - int8_t rs_rssi_ctl1; - int8_t rs_rssi_ctl2; - int8_t rs_rssi_ext0; - int8_t rs_rssi_ext1; - int8_t rs_rssi_ext2; + int8_t rs_rssi_ctl[3]; + int8_t rs_rssi_ext[3]; u8 rs_keyix; u8 rs_rate; u8 rs_antenna; @@ -170,6 +166,7 @@ struct ath_htc_rx_status { u8 rs_num_delims; u8 rs_flags; u8 rs_dummy; + /* FIXME: evm* never used? */ __be32 evm0; __be32 evm1; __be32 evm2; @@ -732,6 +729,7 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning); void ath9k_hw_abortpcurecv(struct ath_hw *ah); bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset); int ath9k_hw_beaconq_setup(struct ath_hw *ah); +void ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set); /* Interrupt Handling */ bool ath9k_hw_intrpend(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5924f72dd49..62ac95d6bb9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -229,16 +229,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); - clear_bit(SC_OP_HW_RESET, &sc->sc_flags); + clear_bit(ATH_OP_HW_RESET, &common->op_flags); ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) { - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) goto work; if (ah->opmode == NL80211_IFTYPE_STATION && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -261,6 +261,8 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) sc->gtt_cnt = 0; ieee80211_wake_queues(sc->hw); + ath9k_p2p_ps_timer(sc); + return true; } @@ -336,7 +338,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand int old_pos = -1; int r; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); @@ -402,7 +404,7 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand chan->center_freq); } else { /* perform spectral scan if requested. */ - if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && + if (test_bit(ATH_OP_SCANNING, &common->op_flags) && sc->spectral_mode == SPECTRAL_CHANSCAN) ath9k_spectral_scan_trigger(hw); } @@ -419,6 +421,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, an->sc = sc; an->sta = sta; an->vif = vif; + memset(&an->key_idx, 0, sizeof(an->key_idx)); ath_tx_node_init(sc, an); } @@ -451,7 +454,7 @@ void ath9k_tasklet(unsigned long data) * interrupts are enabled in the reset routine. */ atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, "FATAL: Skipping interrupts\n"); + ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); goto out; } @@ -471,7 +474,7 @@ void ath9k_tasklet(unsigned long data) * interrupts are enabled in the reset routine. */ atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, + ath_dbg(common, RESET, "BB_WATCHDOG: Skipping interrupts\n"); goto out; } @@ -484,7 +487,7 @@ void ath9k_tasklet(unsigned long data) type = RESET_TYPE_TX_GTT; ath9k_queue_reset(sc, type); atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, + ath_dbg(common, RESET, "GTT: Skipping interrupts\n"); goto out; } @@ -566,6 +569,7 @@ irqreturn_t ath_isr(int irq, void *dev) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; u32 sync_cause = 0; bool sched = false; @@ -575,7 +579,7 @@ irqreturn_t ath_isr(int irq, void *dev) * touch anything. Note this can happen early * on if the IRQ is shared. */ - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return IRQ_NONE; /* shared irq, not for us */ @@ -583,7 +587,7 @@ irqreturn_t ath_isr(int irq, void *dev) if (!ath9k_hw_intrpend(ah)) return IRQ_NONE; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { ath9k_hw_kill_interrupts(ah); return IRQ_HANDLED; } @@ -684,10 +688,11 @@ int ath_reset(struct ath_softc *sc) void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); #ifdef CONFIG_ATH9K_DEBUGFS RESET_STAT_INC(sc, type); #endif - set_bit(SC_OP_HW_RESET, &sc->sc_flags); + set_bit(ATH_OP_HW_RESET, &common->op_flags); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } @@ -768,7 +773,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_mci_enable(sc); - clear_bit(SC_OP_INVALID, &sc->sc_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); sc->sc_ah->is_monitoring = false; if (!ath_complete_reset(sc, false)) @@ -885,7 +890,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath_cancel_work(sc); - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; @@ -940,7 +945,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_ps_restore(sc); - set_bit(SC_OP_INVALID, &sc->sc_flags); + set_bit(ATH_OP_INVALID, &common->op_flags); sc->ps_idle = prev_idle; mutex_unlock(&sc->mutex); @@ -1081,7 +1086,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, */ if (ah->opmode == NL80211_IFTYPE_STATION && old_opmode == NL80211_IFTYPE_AP && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ieee80211_iterate_active_interfaces_atomic( sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, ath9k_sta_vif_iter, sc); @@ -1117,6 +1122,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); + avp->vif = vif; + an->sc = sc; an->sta = NULL; an->vif = vif; @@ -1161,6 +1168,29 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, return 0; } +static void +ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) +{ + struct ath_hw *ah = sc->sc_ah; + s32 tsf, target_tsf; + + if (!avp || !avp->noa.has_next_tsf) + return; + + ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer); + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + + target_tsf = avp->noa.next_tsf; + if (!avp->noa.absent) + target_tsf -= ATH_P2P_PS_STOP_TIME; + + if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) + target_tsf = tsf + ATH_P2P_PS_STOP_TIME; + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000); +} + static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1172,15 +1202,19 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); + spin_lock_bh(&sc->sc_pcu_lock); + if (avp == sc->p2p_ps_vif) { + sc->p2p_ps_vif = NULL; + ath9k_update_p2p_ps_timer(sc, NULL); + } + spin_unlock_bh(&sc->sc_pcu_lock); + sc->nvifs--; sc->tx99_vif = NULL; if (ath9k_uses_beacons(vif->type)) ath9k_beacon_remove_slot(sc, vif); - if (sc->csa_vif == vif) - sc->csa_vif = NULL; - ath9k_ps_wakeup(sc); ath9k_calculate_summary_state(hw, NULL); ath9k_ps_restore(sc); @@ -1428,8 +1462,10 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, return 0; key = ath_key_config(common, vif, sta, &ps_key); - if (key > 0) + if (key > 0) { an->ps_key = key; + an->key_idx[0] = key; + } return 0; } @@ -1447,6 +1483,7 @@ static void ath9k_del_ps_key(struct ath_softc *sc, ath_key_delete(common, &ps_key); an->ps_key = 0; + an->key_idx[0] = 0; } static int ath9k_sta_remove(struct ieee80211_hw *hw, @@ -1461,6 +1498,19 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, return 0; } +static void ath9k_sta_set_tx_filter(struct ath_hw *ah, + struct ath_node *an, + bool set) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { + if (!an->key_idx[i]) + continue; + ath9k_hw_set_tx_filter(ah, an->key_idx[i], set); + } +} + static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, @@ -1473,8 +1523,10 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, case STA_NOTIFY_SLEEP: an->sleeping = true; ath_tx_aggr_sleep(sta, sc, an); + ath9k_sta_set_tx_filter(sc->sc_ah, an, true); break; case STA_NOTIFY_AWAKE: + ath9k_sta_set_tx_filter(sc->sc_ah, an, false); an->sleeping = false; ath_tx_aggr_wakeup(sc, an); break; @@ -1530,7 +1582,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int ret = 0; + struct ath_node *an = NULL; + int ret = 0, i; if (ath9k_modparam_nohwcrypt) return -ENOSPC; @@ -1552,13 +1605,16 @@ static int ath9k_set_key(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ath_dbg(common, CONFIG, "Set HW Key\n"); + ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd); + if (sta) + an = (struct ath_node *)sta->drv_priv; switch (cmd) { case SET_KEY: if (sta) ath9k_del_ps_key(sc, vif, sta); + key->hw_key_idx = 0; ret = ath_key_config(common, vif, sta, key); if (ret >= 0) { key->hw_key_idx = ret; @@ -1571,9 +1627,27 @@ static int ath9k_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; } + if (an && key->hw_key_idx) { + for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { + if (an->key_idx[i]) + continue; + an->key_idx[i] = key->hw_key_idx; + break; + } + WARN_ON(i == ARRAY_SIZE(an->key_idx)); + } break; case DISABLE_KEY: ath_key_delete(common, key); + if (an) { + for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { + if (an->key_idx[i] != key->hw_key_idx) + continue; + an->key_idx[i] = 0; + break; + } + } + key->hw_key_idx = 0; break; default: ret = -EINVAL; @@ -1593,7 +1667,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; unsigned long flags; - set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); avp->primary_sta_vif = true; /* @@ -1609,7 +1683,7 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -1628,14 +1702,75 @@ static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath_softc *sc = data; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) return; if (bss_conf->assoc) ath9k_set_assoc_state(sc, vif); } +void ath9k_p2p_ps_timer(void *priv) +{ + struct ath_softc *sc = priv; + struct ath_vif *avp = sc->p2p_ps_vif; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + struct ath_node *an; + u32 tsf; + + if (!avp) + return; + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + if (!avp->noa.absent) + tsf += ATH_P2P_PS_STOP_TIME; + + if (!avp->noa.has_next_tsf || + avp->noa.next_tsf - tsf > BIT(31)) + ieee80211_update_p2p_noa(&avp->noa, tsf); + + ath9k_update_p2p_ps_timer(sc, avp); + + rcu_read_lock(); + + vif = avp->vif; + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) + goto out; + + an = (void *) sta->drv_priv; + if (an->sleeping == !!avp->noa.absent) + goto out; + + an->sleeping = avp->noa.absent; + if (an->sleeping) + ath_tx_aggr_sleep(sta, sc, an); + else + ath_tx_aggr_wakeup(sc, an); + +out: + rcu_read_unlock(); +} + +void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_vif *avp = (void *)vif->drv_priv; + u32 tsf; + + if (!sc->p2p_ps_timer) + return; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p) + return; + + sc->p2p_ps_vif = avp; + tsf = ath9k_hw_gettsf32(sc->sc_ah); + ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); + ath9k_update_p2p_ps_timer(sc, avp); +} + static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1650,6 +1785,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; + unsigned long flags; int slottime; ath9k_ps_wakeup(sc); @@ -1660,18 +1796,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid, bss_conf->assoc); if (avp->primary_sta_vif && !bss_conf->assoc) { - clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); avp->primary_sta_vif = false; if (ah->opmode == NL80211_IFTYPE_STATION) - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + clear_bit(ATH_OP_BEACONS, &common->op_flags); } ieee80211_iterate_active_interfaces_atomic( sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, ath9k_bss_assoc_iter, sc); - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags) && ah->opmode == NL80211_IFTYPE_STATION) { memset(common->curbssid, 0, ETH_ALEN); common->curaid = 0; @@ -1710,6 +1846,15 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & BSS_CHANGED_P2P_PS) { + spin_lock_bh(&sc->sc_pcu_lock); + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (!(sc->ps_flags & PS_BEACON_SYNC)) + ath9k_update_p2p_ps(sc, vif); + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + spin_unlock_bh(&sc->sc_pcu_lock); + } + if (changed & CHECK_ANI) ath_check_ani(sc); @@ -1866,7 +2011,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) static bool ath9k_has_tx_pending(struct ath_softc *sc) { - int i, npend; + int i, npend = 0; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (!ATH_TXQ_SETUP(sc, i)) @@ -1883,7 +2028,8 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc) return !!npend; } -static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; @@ -1900,7 +2046,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) return; } - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; @@ -2056,7 +2202,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); - ath9k_reload_chainmask_settings(sc); + ath9k_cmn_reload_chainmask(ah); return 0; } @@ -2073,26 +2219,15 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) static void ath9k_sw_scan_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - set_bit(SC_OP_SCANNING, &sc->sc_flags); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + set_bit(ATH_OP_SCANNING, &common->op_flags); } static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - clear_bit(SC_OP_SCANNING, &sc->sc_flags); -} - -static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_chan_def *chandef) -{ - struct ath_softc *sc = hw->priv; - - /* mac80211 does not support CSA in multi-if cases (yet) */ - if (WARN_ON(sc->csa_vif)) - return; - - sc->csa_vif = vif; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + clear_bit(ATH_OP_SCANNING, &common->op_flags); } struct ieee80211_ops ath9k_ops = { @@ -2142,5 +2277,4 @@ struct ieee80211_ops ath9k_ops = { #endif .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, - .channel_switch_beacon = ath9k_channel_switch_beacon, }; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 71799fcade5..a0dbcc41238 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -555,7 +555,7 @@ void ath_mci_intr(struct ath_softc *sc) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return; pgpm = mci->gpm_buf.bf_addr; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 55724b02316..4dec09e565e 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -686,7 +686,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath9k_platform_data *pdata = sc->dev->platform_data; - if (pdata) { + if (pdata && !pdata->use_eeprom) { if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { ath_err(common, "%s: eeprom read failed, offset %08x is out of range\n", @@ -858,9 +858,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = pcim_iomap_table(pdev)[0]; sc->driver_data = id->driver_data; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); @@ -917,6 +914,7 @@ static int ath_pci_suspend(struct device *device) */ ath9k_stop_btcoex(sc); ath9k_hw_disable(sc->sc_ah); + del_timer_sync(&sc->sleep_timer); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); return 0; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c deleted file mode 100644 index d829bb62a3f..00000000000 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ /dev/null @@ -1,1495 +0,0 @@ -/* - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2004-2011 Atheros Communications, 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/slab.h> -#include <linux/export.h> - -#include "ath9k.h" - -static const struct ath_rate_table ar5416_11na_ratetable = { - 68, - 8, /* MCS start */ - { - [0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, - 5400, 0, 12 }, /* 6 Mb */ - [1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, - 7800, 1, 18 }, /* 9 Mb */ - [2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, - 10000, 2, 24 }, /* 12 Mb */ - [3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, - 13900, 3, 36 }, /* 18 Mb */ - [4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, - 17300, 4, 48 }, /* 24 Mb */ - [5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, - 23000, 5, 72 }, /* 36 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, - 27400, 6, 96 }, /* 48 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, - 29300, 7, 108 }, /* 54 Mb */ - [8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500, - 6400, 0, 0 }, /* 6.5 Mb */ - [9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, - 12700, 1, 1 }, /* 13 Mb */ - [10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, - 18800, 2, 2 }, /* 19.5 Mb */ - [11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, - 25000, 3, 3 }, /* 26 Mb */ - [12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, - 36700, 4, 4 }, /* 39 Mb */ - [13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, - 48100, 5, 5 }, /* 52 Mb */ - [14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, - 53500, 6, 6 }, /* 58.5 Mb */ - [15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, - 59000, 7, 7 }, /* 65 Mb */ - [16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, - 65400, 7, 7 }, /* 75 Mb */ - [17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, - 12700, 8, 8 }, /* 13 Mb */ - [18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, - 24800, 9, 9 }, /* 26 Mb */ - [19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, - 36600, 10, 10 }, /* 39 Mb */ - [20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, - 48100, 11, 11 }, /* 52 Mb */ - [21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, - 69500, 12, 12 }, /* 78 Mb */ - [22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, - 89500, 13, 13 }, /* 104 Mb */ - [23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, - 98900, 14, 14 }, /* 117 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, - 108300, 15, 15 }, /* 130 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, - 120000, 15, 15 }, /* 144.4 Mb */ - [26] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, - 17400, 16, 16 }, /* 19.5 Mb */ - [27] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, - 35100, 17, 17 }, /* 39 Mb */ - [28] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, - 52600, 18, 18 }, /* 58.5 Mb */ - [29] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, - 70400, 19, 19 }, /* 78 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, - 104900, 20, 20 }, /* 117 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, - 115800, 20, 20 }, /* 130 Mb*/ - [32] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, - 137200, 21, 21 }, /* 156 Mb */ - [33] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, - 151100, 21, 21 }, /* 173.3 Mb */ - [34] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, - 152800, 22, 22 }, /* 175.5 Mb */ - [35] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, - 168400, 22, 22 }, /* 195 Mb*/ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, - 168400, 23, 23 }, /* 195 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, - 185000, 23, 23 }, /* 216.7 Mb */ - [38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, - 13200, 0, 0 }, /* 13.5 Mb*/ - [39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, - 25900, 1, 1 }, /* 27.0 Mb*/ - [40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, - 38600, 2, 2 }, /* 40.5 Mb*/ - [41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, - 49800, 3, 3 }, /* 54 Mb */ - [42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, - 72200, 4, 4 }, /* 81 Mb */ - [43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000, - 92900, 5, 5 }, /* 108 Mb */ - [44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, - 102700, 6, 6 }, /* 121.5 Mb*/ - [45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, - 112000, 7, 7 }, /* 135 Mb */ - [46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, - 122000, 7, 7 }, /* 150 Mb */ - [47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, - 25800, 8, 8 }, /* 27 Mb */ - [48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, - 49800, 9, 9 }, /* 54 Mb */ - [49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, - 71900, 10, 10 }, /* 81 Mb */ - [50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, - 92500, 11, 11 }, /* 108 Mb */ - [51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, - 130300, 12, 12 }, /* 162 Mb */ - [52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, - 162800, 13, 13 }, /* 216 Mb */ - [53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, - 178200, 14, 14 }, /* 243 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, - 192100, 15, 15 }, /* 270 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, - 207000, 15, 15 }, /* 300 Mb */ - [56] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, - 36100, 16, 16 }, /* 40.5 Mb */ - [57] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, - 72900, 17, 17 }, /* 81 Mb */ - [58] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, - 108300, 18, 18 }, /* 121.5 Mb */ - [59] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, - 142000, 19, 19 }, /* 162 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, - 205100, 20, 20 }, /* 243 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20 }, /* 270 Mb */ - [62] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, - 263100, 21, 21 }, /* 324 Mb */ - [63] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, - 288000, 21, 21 }, /* 360 Mb */ - [64] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, - 290700, 22, 22 }, /* 364.5 Mb */ - [65] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, - 317200, 22, 22 }, /* 405 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, - 317200, 23, 23 }, /* 405 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, - 346400, 23, 23 }, /* 450 Mb */ - }, - 50, /* probe interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -/* 4ms frame limit not used for NG mode. The values filled - * for HT are the 64K max aggregate limit */ - -static const struct ath_rate_table ar5416_11ng_ratetable = { - 72, - 12, /* MCS start */ - { - [0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000, - 900, 0, 2 }, /* 1 Mb */ - [1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000, - 1900, 1, 4 }, /* 2 Mb */ - [2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500, - 4900, 2, 11 }, /* 5.5 Mb */ - [3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000, - 8100, 3, 22 }, /* 11 Mb */ - [4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, - 5400, 4, 12 }, /* 6 Mb */ - [5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, - 7800, 5, 18 }, /* 9 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, - 10100, 6, 24 }, /* 12 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, - 14100, 7, 36 }, /* 18 Mb */ - [8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, - 17700, 8, 48 }, /* 24 Mb */ - [9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, - 23700, 9, 72 }, /* 36 Mb */ - [10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, - 27400, 10, 96 }, /* 48 Mb */ - [11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, - 30900, 11, 108 }, /* 54 Mb */ - [12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500, - 6400, 0, 0 }, /* 6.5 Mb */ - [13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, - 12700, 1, 1 }, /* 13 Mb */ - [14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, - 18800, 2, 2 }, /* 19.5 Mb*/ - [15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, - 25000, 3, 3 }, /* 26 Mb */ - [16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, - 36700, 4, 4 }, /* 39 Mb */ - [17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, - 48100, 5, 5 }, /* 52 Mb */ - [18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, - 53500, 6, 6 }, /* 58.5 Mb */ - [19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, - 59000, 7, 7 }, /* 65 Mb */ - [20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, - 65400, 7, 7 }, /* 65 Mb*/ - [21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, - 12700, 8, 8 }, /* 13 Mb */ - [22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, - 24800, 9, 9 }, /* 26 Mb */ - [23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, - 36600, 10, 10 }, /* 39 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, - 48100, 11, 11 }, /* 52 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, - 69500, 12, 12 }, /* 78 Mb */ - [26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, - 89500, 13, 13 }, /* 104 Mb */ - [27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, - 98900, 14, 14 }, /* 117 Mb */ - [28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, - 108300, 15, 15 }, /* 130 Mb */ - [29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, - 120000, 15, 15 }, /* 144.4 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, - 17400, 16, 16 }, /* 19.5 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, - 35100, 17, 17 }, /* 39 Mb */ - [32] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, - 52600, 18, 18 }, /* 58.5 Mb */ - [33] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, - 70400, 19, 19 }, /* 78 Mb */ - [34] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, - 104900, 20, 20 }, /* 117 Mb */ - [35] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, - 115800, 20, 20 }, /* 130 Mb */ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, - 137200, 21, 21 }, /* 156 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, - 151100, 21, 21 }, /* 173.3 Mb */ - [38] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, - 152800, 22, 22 }, /* 175.5 Mb */ - [39] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, - 168400, 22, 22 }, /* 195 Mb */ - [40] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, - 168400, 23, 23 }, /* 195 Mb */ - [41] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, - 185000, 23, 23 }, /* 216.7 Mb */ - [42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, - 13200, 0, 0 }, /* 13.5 Mb */ - [43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, - 25900, 1, 1 }, /* 27.0 Mb */ - [44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, - 38600, 2, 2 }, /* 40.5 Mb */ - [45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, - 49800, 3, 3 }, /* 54 Mb */ - [46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, - 72200, 4, 4 }, /* 81 Mb */ - [47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000, - 92900, 5, 5 }, /* 108 Mb */ - [48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, - 102700, 6, 6 }, /* 121.5 Mb */ - [49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, - 112000, 7, 7 }, /* 135 Mb */ - [50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, - 122000, 7, 7 }, /* 150 Mb */ - [51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, - 25800, 8, 8 }, /* 27 Mb */ - [52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, - 49800, 9, 9 }, /* 54 Mb */ - [53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, - 71900, 10, 10 }, /* 81 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, - 92500, 11, 11 }, /* 108 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, - 130300, 12, 12 }, /* 162 Mb */ - [56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, - 162800, 13, 13 }, /* 216 Mb */ - [57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, - 178200, 14, 14 }, /* 243 Mb */ - [58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, - 192100, 15, 15 }, /* 270 Mb */ - [59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, - 207000, 15, 15 }, /* 300 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, - 36100, 16, 16 }, /* 40.5 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, - 72900, 17, 17 }, /* 81 Mb */ - [62] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, - 108300, 18, 18 }, /* 121.5 Mb */ - [63] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, - 142000, 19, 19 }, /* 162 Mb */ - [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, - 205100, 20, 20 }, /* 243 Mb */ - [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20 }, /* 270 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, - 263100, 21, 21 }, /* 324 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, - 288000, 21, 21 }, /* 360 Mb */ - [68] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, - 290700, 22, 22 }, /* 364.5 Mb */ - [69] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, - 317200, 22, 22 }, /* 405 Mb */ - [70] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, - 317200, 23, 23 }, /* 405 Mb */ - [71] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, - 346400, 23, 23 }, /* 450 Mb */ - }, - 50, /* probe interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11a_ratetable = { - 8, - 0, - { - { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0, 12}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 1, 18}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 2, 24}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 3, 36}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 4, 48}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 5, 72}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 6, 96}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 7, 108}, - }, - 50, /* probe interval */ - 0, /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11g_ratetable = { - 12, - 0, - { - { RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0, 2}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 1, 4}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 2, 11}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 3, 22}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 4, 12}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 5, 18}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 6, 24}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 7, 36}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 8, 48}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 9, 72}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 10, 96}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 11, 108}, - }, - 50, /* probe interval */ - 0, /* Phy rates allowed initially */ -}; - -static int ath_rc_get_rateindex(struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_rate *rate) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - int rix, i, idx = 0; - - if (!(rate->flags & IEEE80211_TX_RC_MCS)) - return rate->idx; - - for (i = 0; i < ath_rc_priv->max_valid_rate; i++) { - idx = ath_rc_priv->valid_rate_index[i]; - - if (WLAN_RC_PHY_HT(rate_table->info[idx].phy) && - rate_table->info[idx].ratecode == rate->idx) - break; - } - - rix = idx; - - if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - rix++; - - return rix; -} - -static void ath_rc_sort_validrates(struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u8 i, j, idx, idx_next; - - for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { - for (j = 0; j <= i-1; j++) { - idx = ath_rc_priv->valid_rate_index[j]; - idx_next = ath_rc_priv->valid_rate_index[j+1]; - - if (rate_table->info[idx].ratekbps > - rate_table->info[idx_next].ratekbps) { - ath_rc_priv->valid_rate_index[j] = idx_next; - ath_rc_priv->valid_rate_index[j+1] = idx; - } - } - } -} - -static inline -int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, - u8 *next_idx) -{ - u8 i; - - for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i+1]; - return 1; - } - } - - /* No more valid rates */ - *next_idx = 0; - - return 0; -} - -/* Return true only for single stream */ - -static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) -{ - if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG)) - return 0; - if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) - return 0; - if (WLAN_RC_PHY_TS(phy) && !(capflag & WLAN_RC_TS_FLAG)) - return 0; - if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) - return 0; - if (!ignore_cw && WLAN_RC_PHY_HT(phy)) - if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) - return 0; - return 1; -} - -static inline int -ath_rc_get_lower_rix(struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, u8 *next_idx) -{ - int8_t i; - - for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i-1]; - return 1; - } - } - - return 0; -} - -static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u8 i, hi = 0; - - for (i = 0; i < rate_table->rate_cnt; i++) { - if (rate_table->info[i].rate_flags & RC_LEGACY) { - u32 phy = rate_table->info[i].phy; - u8 valid_rate_count = 0; - - if (!ath_rc_valid_phyrate(phy, ath_rc_priv->ht_cap, 0)) - continue; - - valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - - ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_priv->valid_rate_index[i] = true; - hi = i; - } - } - - return hi; -} - -static inline bool ath_rc_check_legacy(u8 rate, u8 dot11rate, u16 rate_flags, - u32 phy, u32 capflag) -{ - if (rate != dot11rate || WLAN_RC_PHY_HT(phy)) - return false; - - if ((rate_flags & WLAN_RC_CAP_MODE(capflag)) != WLAN_RC_CAP_MODE(capflag)) - return false; - - if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) - return false; - - return true; -} - -static inline bool ath_rc_check_ht(u8 rate, u8 dot11rate, u16 rate_flags, - u32 phy, u32 capflag) -{ - if (rate != dot11rate || !WLAN_RC_PHY_HT(phy)) - return false; - - if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag)) - return false; - - if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) - return false; - - return true; -} - -static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, bool legacy) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - struct ath_rateset *rateset; - u32 phy, capflag = ath_rc_priv->ht_cap; - u16 rate_flags; - u8 i, j, hi = 0, rate, dot11rate, valid_rate_count; - - if (legacy) - rateset = &ath_rc_priv->neg_rates; - else - rateset = &ath_rc_priv->neg_ht_rates; - - for (i = 0; i < rateset->rs_nrates; i++) { - for (j = 0; j < rate_table->rate_cnt; j++) { - phy = rate_table->info[j].phy; - rate_flags = rate_table->info[j].rate_flags; - rate = rateset->rs_rates[i]; - dot11rate = rate_table->info[j].dot11rate; - - if (legacy && - !ath_rc_check_legacy(rate, dot11rate, - rate_flags, phy, capflag)) - continue; - - if (!legacy && - !ath_rc_check_ht(rate, dot11rate, - rate_flags, phy, capflag)) - continue; - - if (!ath_rc_valid_phyrate(phy, capflag, 0)) - continue; - - valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = j; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_priv->valid_rate_index[j] = true; - hi = max(hi, j); - } - } - - return hi; -} - -static u8 ath_rc_get_highest_rix(struct ath_rate_priv *ath_rc_priv, - int *is_probing) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u32 best_thruput, this_thruput, now_msec; - u8 rate, next_rate, best_rate, maxindex, minindex; - int8_t index = 0; - - now_msec = jiffies_to_msecs(jiffies); - *is_probing = 0; - best_thruput = 0; - maxindex = ath_rc_priv->max_valid_rate-1; - minindex = 0; - best_rate = minindex; - - /* - * Try the higher rate first. It will reduce memory moving time - * if we have very good channel characteristics. - */ - for (index = maxindex; index >= minindex ; index--) { - u8 per_thres; - - rate = ath_rc_priv->valid_rate_index[index]; - if (rate > ath_rc_priv->rate_max_phy) - continue; - - /* - * For TCP the average collision rate is around 11%, - * so we ignore PERs less than this. This is to - * prevent the rate we are currently using (whose - * PER might be in the 10-15 range because of TCP - * collisions) looking worse than the next lower - * rate whose PER has decayed close to 0. If we - * used to next lower rate, its PER would grow to - * 10-15 and we would be worse off then staying - * at the current rate. - */ - per_thres = ath_rc_priv->per[rate]; - if (per_thres < 12) - per_thres = 12; - - this_thruput = rate_table->info[rate].user_ratekbps * - (100 - per_thres); - - if (best_thruput <= this_thruput) { - best_thruput = this_thruput; - best_rate = rate; - } - } - - rate = best_rate; - - /* - * Must check the actual rate (ratekbps) to account for - * non-monoticity of 11g's rate table - */ - - if (rate >= ath_rc_priv->rate_max_phy) { - rate = ath_rc_priv->rate_max_phy; - - /* Probe the next allowed phy state */ - if (ath_rc_get_nextvalid_txrate(rate_table, - ath_rc_priv, rate, &next_rate) && - (now_msec - ath_rc_priv->probe_time > - rate_table->probe_interval) && - (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { - rate = next_rate; - ath_rc_priv->probe_rate = rate; - ath_rc_priv->probe_time = now_msec; - ath_rc_priv->hw_maxretry_pktcnt = 0; - *is_probing = 1; - } - } - - if (rate > (ath_rc_priv->rate_table_size - 1)) - rate = ath_rc_priv->rate_table_size - 1; - - if (RC_TS_ONLY(rate_table->info[rate].rate_flags) && - (ath_rc_priv->ht_cap & WLAN_RC_TS_FLAG)) - return rate; - - if (RC_DS_OR_LATER(rate_table->info[rate].rate_flags) && - (ath_rc_priv->ht_cap & (WLAN_RC_DS_FLAG | WLAN_RC_TS_FLAG))) - return rate; - - if (RC_SS_OR_LEGACY(rate_table->info[rate].rate_flags)) - return rate; - - /* This should not happen */ - WARN_ON_ONCE(1); - - rate = ath_rc_priv->valid_rate_index[0]; - - return rate; -} - -static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, - struct ieee80211_tx_rate *rate, - struct ieee80211_tx_rate_control *txrc, - u8 tries, u8 rix, int rtsctsenable) -{ - rate->count = tries; - rate->idx = rate_table->info[rix].ratecode; - - if (txrc->rts || rtsctsenable) - rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; - - if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) { - rate->flags |= IEEE80211_TX_RC_MCS; - if (WLAN_RC_PHY_40(rate_table->info[rix].phy) && - conf_is_ht40(&txrc->hw->conf)) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_SHORT_GI; - } -} - -static void ath_rc_rate_set_rtscts(struct ath_softc *sc, - const struct ath_rate_table *rate_table, - struct ieee80211_tx_info *tx_info) -{ - struct ieee80211_bss_conf *bss_conf; - - if (!tx_info->control.vif) - return; - /* - * For legacy frames, mac80211 takes care of CTS protection. - */ - if (!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) - return; - - bss_conf = &tx_info->control.vif->bss_conf; - - if (!bss_conf->basic_rates) - return; - - /* - * For now, use the lowest allowed basic rate for HT frames. - */ - tx_info->control.rts_cts_rate_idx = __ffs(bss_conf->basic_rates); -} - -static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - const struct ath_rate_table *rate_table; - struct sk_buff *skb = txrc->skb; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - u8 try_per_rate, i = 0, rix; - int is_probe = 0; - - if (rate_control_send_low(sta, priv_sta, txrc)) - return; - - /* - * For Multi Rate Retry we use a different number of - * retry attempt counts. This ends up looking like this: - * - * MRR[0] = 4 - * MRR[1] = 4 - * MRR[2] = 4 - * MRR[3] = 8 - * - */ - try_per_rate = 4; - - rate_table = ath_rc_priv->rate_table; - rix = ath_rc_get_highest_rix(ath_rc_priv, &is_probe); - - if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) - tx_info->flags |= IEEE80211_TX_CTL_LDPC; - - if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) - tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT); - - if (is_probe) { - /* - * Set one try for probe rates. For the - * probes don't enable RTS. - */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - 1, rix, 0); - /* - * Get the next tried/allowed rate. - * No RTS for the next series after the probe rate. - */ - ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); - - tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } else { - /* - * Set the chosen rate. No RTS for first series entry. - */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); - } - - for ( ; i < 4; i++) { - /* - * Use twice the number of tries for the last MRR segment. - */ - if (i + 1 == 4) - try_per_rate = 8; - - ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); - - /* - * All other rates in the series have RTS enabled. - */ - ath_rc_rate_set_series(rate_table, &rates[i], txrc, - try_per_rate, rix, 1); - } - - /* - * NB:Change rate series to enable aggregation when operating - * at lower MCS rates. When first rate in series is MCS2 - * in HT40 @ 2.4GHz, series should look like: - * - * {MCS2, MCS1, MCS0, MCS0}. - * - * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should - * look like: - * - * {MCS3, MCS2, MCS1, MCS1} - * - * So, set fourth rate in series to be same as third one for - * above conditions. - */ - if ((sc->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) && - (conf_is_ht(&sc->hw->conf))) { - u8 dot11rate = rate_table->info[rix].dot11rate; - u8 phy = rate_table->info[rix].phy; - if (i == 4 && - ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || - (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { - rates[3].idx = rates[2].idx; - rates[3].flags = rates[2].flags; - } - } - - /* - * Force hardware to use computed duration for next - * fragment by disabling multi-rate retry, which - * updates duration based on the multi-rate duration table. - * - * FIXME: Fix duration - */ - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - rates[1].count = rates[2].count = rates[3].count = 0; - rates[1].idx = rates[2].idx = rates[3].idx = 0; - rates[0].count = ATH_TXMAXTRY; - } - - ath_rc_rate_set_rtscts(sc, rate_table, tx_info); -} - -static void ath_rc_update_per(struct ath_softc *sc, - const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_info *tx_info, - int tx_rate, int xretries, int retries, - u32 now_msec) -{ - int count, n_bad_frames; - u8 last_per; - static const u32 nretry_to_per_lookup[10] = { - 100 * 0 / 1, - 100 * 1 / 4, - 100 * 1 / 2, - 100 * 3 / 4, - 100 * 4 / 5, - 100 * 5 / 6, - 100 * 6 / 7, - 100 * 7 / 8, - 100 * 8 / 9, - 100 * 9 / 10 - }; - - last_per = ath_rc_priv->per[tx_rate]; - n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len; - - if (xretries) { - if (xretries == 1) { - ath_rc_priv->per[tx_rate] += 30; - if (ath_rc_priv->per[tx_rate] > 100) - ath_rc_priv->per[tx_rate] = 100; - } else { - /* xretries == 2 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - ath_rc_priv->per[tx_rate] = - (u8)(last_per - (last_per >> 3) + (100 >> 3)); - } - - /* xretries == 1 or 2 */ - - if (ath_rc_priv->probe_rate == tx_rate) - ath_rc_priv->probe_rate = 0; - - } else { /* xretries == 0 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - if (n_bad_frames) { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) - * Assuming that n_frames is not 0. The current PER - * from the retries is 100 * retries / (retries+1), - * since the first retries attempts failed, and the - * next one worked. For the one that worked, - * n_bad_frames subframes out of n_frames wored, - * so the PER for that part is - * 100 * n_bad_frames / n_frames, and it contributes - * 100 * n_bad_frames / (n_frames * (retries+1)) to - * the above PER. The expression below is a - * simplified version of the sum of these two terms. - */ - if (tx_info->status.ampdu_len > 0) { - int n_frames, n_bad_tries; - u8 cur_per, new_per; - - n_bad_tries = retries * tx_info->status.ampdu_len + - n_bad_frames; - n_frames = tx_info->status.ampdu_len * (retries + 1); - cur_per = (100 * n_bad_tries / n_frames) >> 3; - new_per = (u8)(last_per - (last_per >> 3) + cur_per); - ath_rc_priv->per[tx_rate] = new_per; - } - } else { - ath_rc_priv->per[tx_rate] = - (u8)(last_per - (last_per >> 3) + - (nretry_to_per_lookup[retries] >> 3)); - } - - - /* - * If we got at most one retry then increase the max rate if - * this was a probe. Otherwise, ignore the probe. - */ - if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { - if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) { - /* - * Since we probed with just a single attempt, - * any retries means the probe failed. Also, - * if the attempt worked, but more than half - * the subframes were bad then also consider - * the probe a failure. - */ - ath_rc_priv->probe_rate = 0; - } else { - u8 probe_rate = 0; - - ath_rc_priv->rate_max_phy = - ath_rc_priv->probe_rate; - probe_rate = ath_rc_priv->probe_rate; - - if (ath_rc_priv->per[probe_rate] > 30) - ath_rc_priv->per[probe_rate] = 20; - - ath_rc_priv->probe_rate = 0; - - /* - * Since this probe succeeded, we allow the next - * probe twice as soon. This allows the maxRate - * to move up faster if the probes are - * successful. - */ - ath_rc_priv->probe_time = - now_msec - rate_table->probe_interval / 2; - } - } - - if (retries > 0) { - /* - * Don't update anything. We don't know if - * this was because of collisions or poor signal. - */ - ath_rc_priv->hw_maxretry_pktcnt = 0; - } else { - /* - * It worked with no retries. First ignore bogus (small) - * rssi_ack values. - */ - if (tx_rate == ath_rc_priv->rate_max_phy && - ath_rc_priv->hw_maxretry_pktcnt < 255) { - ath_rc_priv->hw_maxretry_pktcnt++; - } - - } - } -} - -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_info *tx_info, - int tx_rate, int xretries, int retries) -{ - u32 now_msec = jiffies_to_msecs(jiffies); - int rate; - u8 last_per; - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - int size = ath_rc_priv->rate_table_size; - - if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) - return; - - last_per = ath_rc_priv->per[tx_rate]; - - /* Update PER first */ - ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info, tx_rate, xretries, - retries, now_msec); - - /* - * If this rate looks bad (high PER) then stop using it for - * a while (except if we are probing). - */ - if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 && - rate_table->info[tx_rate].ratekbps <= - rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { - ath_rc_get_lower_rix(ath_rc_priv, (u8)tx_rate, - &ath_rc_priv->rate_max_phy); - - /* Don't probe for a little while. */ - ath_rc_priv->probe_time = now_msec; - } - - /* Make sure the rates below this have lower PER */ - /* Monotonicity is kept only for rates below the current rate. */ - if (ath_rc_priv->per[tx_rate] < last_per) { - for (rate = tx_rate - 1; rate >= 0; rate--) { - - if (ath_rc_priv->per[rate] > - ath_rc_priv->per[rate+1]) { - ath_rc_priv->per[rate] = - ath_rc_priv->per[rate+1]; - } - } - } - - /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < size - 1; rate++) { - if (ath_rc_priv->per[rate+1] < - ath_rc_priv->per[rate]) - ath_rc_priv->per[rate+1] = - ath_rc_priv->per[rate]; - } - - /* Every so often, we reduce the thresholds - * and PER (different for CCK and OFDM). */ - if (now_msec - ath_rc_priv->per_down_time >= - rate_table->probe_interval) { - for (rate = 0; rate < size; rate++) { - ath_rc_priv->per[rate] = - 7 * ath_rc_priv->per[rate] / 8; - } - - ath_rc_priv->per_down_time = now_msec; - } - - ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries, - ath_rc_priv->per[tx_rate]); - -} - -static void ath_rc_tx_status(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - struct ieee80211_tx_rate *rate; - int final_ts_idx = 0, xretries = 0, long_retry = 0; - u8 flags; - u32 i = 0, rix; - - for (i = 0; i < sc->hw->max_rates; i++) { - rate = &tx_info->status.rates[i]; - if (rate->idx < 0 || !rate->count) - break; - - final_ts_idx = i; - long_retry = rate->count - 1; - } - - if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) - xretries = 1; - - /* - * If the first rate is not the final index, there - * are intermediate rate failures to be processed. - */ - if (final_ts_idx != 0) { - for (i = 0; i < final_ts_idx ; i++) { - if (rates[i].count != 0 && (rates[i].idx >= 0)) { - flags = rates[i].flags; - - /* If HT40 and we have switched mode from - * 40 to 20 => don't update */ - - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(ath_rc_priv, &rates[i]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info, - rix, xretries ? 1 : 2, - rates[i].count); - } - } - } - - flags = rates[final_ts_idx].flags; - - /* If HT40 and we have switched mode from 40 to 20 => don't update */ - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(ath_rc_priv, &rates[final_ts_idx]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry); - ath_debug_stat_rc(ath_rc_priv, rix); -} - -static const -struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, - enum ieee80211_band band, - bool is_ht) -{ - switch(band) { - case IEEE80211_BAND_2GHZ: - if (is_ht) - return &ar5416_11ng_ratetable; - return &ar5416_11g_ratetable; - case IEEE80211_BAND_5GHZ: - if (is_ht) - return &ar5416_11na_ratetable; - return &ar5416_11a_ratetable; - default: - return NULL; - } -} - -static void ath_rc_init(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - struct ath_rateset *rateset = &ath_rc_priv->neg_rates; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u8 i, j, k, hi = 0, hthi = 0; - - ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; - - for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->per[i] = 0; - ath_rc_priv->valid_rate_index[i] = 0; - } - - for (i = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < RATE_TABLE_SIZE; j++) - ath_rc_priv->valid_phy_rateidx[i][j] = 0; - ath_rc_priv->valid_phy_ratecnt[i] = 0; - } - - if (!rateset->rs_nrates) { - hi = ath_rc_init_validrates(ath_rc_priv); - } else { - hi = ath_rc_setvalid_rates(ath_rc_priv, true); - - if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) - hthi = ath_rc_setvalid_rates(ath_rc_priv, false); - - hi = max(hi, hthi); - } - - ath_rc_priv->rate_table_size = hi + 1; - ath_rc_priv->rate_max_phy = 0; - WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); - - for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { - ath_rc_priv->valid_rate_index[k++] = - ath_rc_priv->valid_phy_rateidx[i][j]; - } - - if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) || - !ath_rc_priv->valid_phy_ratecnt[i]) - continue; - - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; - } - WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); - WARN_ON(k > RATE_TABLE_SIZE); - - ath_rc_priv->max_valid_rate = k; - ath_rc_sort_validrates(ath_rc_priv); - ath_rc_priv->rate_max_phy = (k > 4) ? - ath_rc_priv->valid_rate_index[k-4] : - ath_rc_priv->valid_rate_index[k-1]; - - ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n", - ath_rc_priv->ht_cap); -} - -static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) -{ - u8 caps = 0; - - if (sta->ht_cap.ht_supported) { - caps = WLAN_RC_HT_FLAG; - if (sta->ht_cap.mcs.rx_mask[1] && sta->ht_cap.mcs.rx_mask[2]) - caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; - else if (sta->ht_cap.mcs.rx_mask[1]) - caps |= WLAN_RC_DS_FLAG; - if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { - caps |= WLAN_RC_40_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) - caps |= WLAN_RC_SGI_FLAG; - } else { - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) - caps |= WLAN_RC_SGI_FLAG; - } - } - - return caps; -} - -static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta, - u8 tidno) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - struct ath_atx_tid *txtid; - - if (!sta->ht_cap.ht_supported) - return false; - - txtid = ATH_AN_2_TID(an, tidno); - return !txtid->active; -} - - -/***********************************/ -/* mac80211 Rate Control callbacks */ -/***********************************/ - -static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - - if (!priv_sta || !ieee80211_is_data(fc)) - return; - - /* This packet was aggregated but doesn't carry status info */ - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && - !(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) - return; - - if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) - return; - - ath_rc_tx_status(sc, ath_rc_priv, skb); - - /* Check if aggregation has to be enabled for this tid */ - if (conf_is_ht(&sc->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc) && - skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { - u8 *qc, tid; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - - if(ath_tx_aggr_check(sc, sta, tid)) - ieee80211_start_tx_ba_session(sta, tid, 0); - } - } -} - -static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, - struct cfg80211_chan_def *chandef, - struct ieee80211_sta *sta, void *priv_sta) -{ - struct ath_softc *sc = priv; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_rate_priv *ath_rc_priv = priv_sta; - int i, j = 0; - u32 rate_flags = ieee80211_chandef_rate_flags(&sc->hw->conf.chandef); - - for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { - if ((rate_flags & sband->bitrates[i].flags) - != rate_flags) - continue; - - ath_rc_priv->neg_rates.rs_rates[j] - = (sband->bitrates[i].bitrate * 2) / 10; - j++; - } - } - ath_rc_priv->neg_rates.rs_nrates = j; - - if (sta->ht_cap.ht_supported) { - for (i = 0, j = 0; i < 77; i++) { - if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) - ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; - if (j == ATH_RATE_MAX) - break; - } - ath_rc_priv->neg_ht_rates.rs_nrates = j; - } - - ath_rc_priv->rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported); - if (!ath_rc_priv->rate_table) { - ath_err(common, "No rate table chosen\n"); - return; - } - - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); - ath_rc_init(sc, priv_sta); -} - -static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, - struct cfg80211_chan_def *chandef, - struct ieee80211_sta *sta, void *priv_sta, - u32 changed) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - - if (changed & IEEE80211_RC_BW_CHANGED) { - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); - ath_rc_init(sc, priv_sta); - - ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, - "Operating Bandwidth changed to: %d\n", - sc->hw->conf.chandef.width); - } -} - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ - struct ath_rc_stats *stats; - - stats = &rc->rcstats[final_rate]; - stats->success++; -} - -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ - struct ath_rc_stats *stats = &rc->rcstats[rix]; - - stats->xretries += xretries; - stats->retries += retries; - stats->per = per; -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_rate_priv *rc = file->private_data; - char *buf; - unsigned int len = 0, max; - int rix; - ssize_t retval; - - if (rc->rate_table == NULL) - return 0; - - max = 80 + rc->rate_table_size * 1024 + 1; - buf = kmalloc(max, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += sprintf(buf, "%6s %6s %6s " - "%10s %10s %10s %10s\n", - "HT", "MCS", "Rate", - "Success", "Retries", "XRetries", "PER"); - - for (rix = 0; rix < rc->max_valid_rate; rix++) { - u8 i = rc->valid_rate_index[rix]; - u32 ratekbps = rc->rate_table->info[i].ratekbps; - struct ath_rc_stats *stats = &rc->rcstats[i]; - char mcs[5]; - char htmode[5]; - int used_mcs = 0, used_htmode = 0; - - if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) { - used_mcs = scnprintf(mcs, 5, "%d", - rc->rate_table->info[i].ratecode); - - if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy)) - used_htmode = scnprintf(htmode, 5, "HT40"); - else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy)) - used_htmode = scnprintf(htmode, 5, "HT20"); - else - used_htmode = scnprintf(htmode, 5, "????"); - } - - mcs[used_mcs] = '\0'; - htmode[used_htmode] = '\0'; - - len += scnprintf(buf + len, max - len, - "%6s %6s %3u.%d: " - "%10u %10u %10u %10u\n", - htmode, - mcs, - ratekbps / 1000, - (ratekbps % 1000) / 100, - stats->success, - stats->retries, - stats->xretries, - stats->per); - } - - if (len > max) - len = max; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return retval; -} - -static const struct file_operations fops_rcstat = { - .read = read_file_rcstat, - .open = simple_open, - .owner = THIS_MODULE -}; - -static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, - struct dentry *dir) -{ - struct ath_rate_priv *rc = priv_sta; - rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO, - dir, rc, &fops_rcstat); -} - -static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta) -{ - struct ath_rate_priv *rc = priv_sta; - debugfs_remove(rc->debugfs_rcstats); -} - -#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */ - -static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ - return hw->priv; -} - -static void ath_rate_free(void *priv) -{ - return; -} - -static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) -{ - return kzalloc(sizeof(struct ath_rate_priv), gfp); -} - -static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, - void *priv_sta) -{ - struct ath_rate_priv *rate_priv = priv_sta; - kfree(rate_priv); -} - -static struct rate_control_ops ath_rate_ops = { - .module = NULL, - .name = "ath9k_rate_control", - .tx_status = ath_tx_status, - .get_rate = ath_get_rate, - .rate_init = ath_rate_init, - .rate_update = ath_rate_update, - .alloc = ath_rate_alloc, - .free = ath_rate_free, - .alloc_sta = ath_rate_alloc_sta, - .free_sta = ath_rate_free_sta, - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - .add_sta_debugfs = ath_rate_add_sta_debugfs, - .remove_sta_debugfs = ath_rate_remove_sta_debugfs, -#endif -}; - -int ath_rate_control_register(void) -{ - return ieee80211_rate_control_register(&ath_rate_ops); -} - -void ath_rate_control_unregister(void) -{ - ieee80211_rate_control_unregister(&ath_rate_ops); -} diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h deleted file mode 100644 index b9a87383cb4..00000000000 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2004 Sam Leffler, Errno Consulting - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2008-2011 Atheros Communications 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 RC_H -#define RC_H - -#include "hw.h" - -struct ath_softc; - -#define ATH_RATE_MAX 30 -#define RATE_TABLE_SIZE 72 - -#define RC_INVALID 0x0000 -#define RC_LEGACY 0x0001 -#define RC_SS 0x0002 -#define RC_DS 0x0004 -#define RC_TS 0x0008 -#define RC_HT_20 0x0010 -#define RC_HT_40 0x0020 - -#define RC_STREAM_MASK 0xe -#define RC_DS_OR_LATER(f) ((((f) & RC_STREAM_MASK) == RC_DS) || \ - (((f) & RC_STREAM_MASK) == (RC_DS | RC_TS))) -#define RC_TS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_TS) -#define RC_SS_OR_LEGACY(f) ((f) & (RC_SS | RC_LEGACY)) - -#define RC_HT_2040 (RC_HT_20 | RC_HT_40) -#define RC_ALL_STREAM (RC_SS | RC_DS | RC_TS) -#define RC_L_SD (RC_LEGACY | RC_SS | RC_DS) -#define RC_L_SDT (RC_LEGACY | RC_SS | RC_DS | RC_TS) -#define RC_HT_S_20 (RC_HT_20 | RC_SS) -#define RC_HT_D_20 (RC_HT_20 | RC_DS) -#define RC_HT_T_20 (RC_HT_20 | RC_TS) -#define RC_HT_S_40 (RC_HT_40 | RC_SS) -#define RC_HT_D_40 (RC_HT_40 | RC_DS) -#define RC_HT_T_40 (RC_HT_40 | RC_TS) - -#define RC_HT_SD_20 (RC_HT_20 | RC_SS | RC_DS) -#define RC_HT_DT_20 (RC_HT_20 | RC_DS | RC_TS) -#define RC_HT_SD_40 (RC_HT_40 | RC_SS | RC_DS) -#define RC_HT_DT_40 (RC_HT_40 | RC_DS | RC_TS) - -#define RC_HT_SD_2040 (RC_HT_2040 | RC_SS | RC_DS) -#define RC_HT_SDT_2040 (RC_HT_2040 | RC_SS | RC_DS | RC_TS) - -#define RC_HT_SDT_20 (RC_HT_20 | RC_SS | RC_DS | RC_TS) -#define RC_HT_SDT_40 (RC_HT_40 | RC_SS | RC_DS | RC_TS) - -#define RC_ALL (RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM) - -enum { - WLAN_RC_PHY_OFDM, - WLAN_RC_PHY_CCK, - WLAN_RC_PHY_HT_20_SS, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_20_TS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_40_TS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_20_TS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - WLAN_RC_PHY_HT_40_TS_HGI, - WLAN_RC_PHY_MAX -}; - -#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_TS(_phy) ((_phy == WLAN_RC_PHY_HT_20_TS) \ - || (_phy == WLAN_RC_PHY_HT_40_TS) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_TS) \ - || (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI)) -#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_TS) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) - -#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) - -#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ - ((capflag & WLAN_RC_40_FLAG) ? RC_HT_40 : RC_HT_20) : RC_LEGACY)) - -#define WLAN_RC_CAP_STREAM(capflag) (((capflag & WLAN_RC_TS_FLAG) ? \ - (RC_TS) : ((capflag & WLAN_RC_DS_FLAG) ? RC_DS : RC_SS))) - -/* Return TRUE if flag supports HT20 && client supports HT20 or - * return TRUE if flag supports HT40 && client supports HT40. - * This is used becos some rates overlap between HT20/HT40. - */ -#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ - (((flag & RC_HT_20) && !(capflag & WLAN_RC_40_FLAG)) || \ - ((flag & RC_HT_40) && (capflag & WLAN_RC_40_FLAG))) - -#define WLAN_RC_DS_FLAG (0x01) -#define WLAN_RC_TS_FLAG (0x02) -#define WLAN_RC_40_FLAG (0x04) -#define WLAN_RC_SGI_FLAG (0x08) -#define WLAN_RC_HT_FLAG (0x10) - -/** - * struct ath_rate_table - Rate Control table - * @rate_cnt: total number of rates for the given wireless mode - * @mcs_start: MCS rate index offset - * @rate_flags: Rate Control flags - * @phy: CCK/OFDM/HT20/HT40 - * @ratekbps: rate in Kbits per second - * @user_ratekbps: user rate in Kbits per second - * @ratecode: rate that goes into HW descriptors - * @dot11rate: value that goes into supported - * rates info element of MLME - * @ctrl_rate: Index of next lower basic rate, used for duration computation - * @cw40index: Index of rates having 40MHz channel width - * @sgi_index: Index of rates having Short Guard Interval - * @ht_index: high throughput rates having 40MHz channel width and - * Short Guard Interval - * @probe_interval: interval for rate control to probe for other rates - * @initial_ratemax: initial ratemax value - */ -struct ath_rate_table { - int rate_cnt; - int mcs_start; - struct { - u16 rate_flags; - u8 phy; - u32 ratekbps; - u32 user_ratekbps; - u8 ratecode; - u8 dot11rate; - } info[RATE_TABLE_SIZE]; - u32 probe_interval; - u8 initial_ratemax; -}; - -struct ath_rateset { - u8 rs_nrates; - u8 rs_rates[ATH_RATE_MAX]; -}; - -struct ath_rc_stats { - u32 success; - u32 retries; - u32 xretries; - u8 per; -}; - -/** - * struct ath_rate_priv - Rate Control priv data - * @state: RC state - * @probe_rate: rate we are probing at - * @probe_time: msec timestamp for last probe - * @hw_maxretry_pktcnt: num of packets since we got HW max retry error - * @max_valid_rate: maximum number of valid rate - * @per_down_time: msec timestamp for last PER down step - * @valid_phy_ratecnt: valid rate count - * @rate_max_phy: phy index for the max rate - * @per: PER for every valid rate in % - * @probe_interval: interval for ratectrl to probe for other rates - * @ht_cap: HT capabilities - * @neg_rates: Negotatied rates - * @neg_ht_rates: Negotiated HT rates - */ -struct ath_rate_priv { - u8 rate_table_size; - u8 probe_rate; - u8 hw_maxretry_pktcnt; - u8 max_valid_rate; - u8 valid_rate_index[RATE_TABLE_SIZE]; - u8 ht_cap; - u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; - u8 rate_max_phy; - u8 per[RATE_TABLE_SIZE]; - u32 probe_time; - u32 per_down_time; - u32 probe_interval; - struct ath_rateset neg_rates; - struct ath_rateset neg_ht_rates; - const struct ath_rate_table *rate_table; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - struct dentry *debugfs_rcstats; - struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; -#endif -}; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate); -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per); -#else -static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ -} -static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ -} -#endif - -#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL -int ath_rate_control_register(void); -void ath_rate_control_unregister(void); -#else -static inline int ath_rate_control_register(void) -{ - return 0; -} - -static inline void ath_rate_control_unregister(void) -{ -} -#endif - -#endif /* RC_H */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 82e340d3ec6..9105a92364f 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) * buffer (or rx fifo). This can incorrectly acknowledge packets * to a sender if last desc is self-linked. */ -static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf) +static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf, + bool flush) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf) common->rx_bufsize, 0); - if (sc->rx.rxlink == NULL) - ath9k_hw_putrxbuf(ah, bf->bf_daddr); - else + if (sc->rx.rxlink) *sc->rx.rxlink = bf->bf_daddr; + else if (!flush) + ath9k_hw_putrxbuf(ah, bf->bf_daddr); sc->rx.rxlink = &ds->ds_link; } -static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf) +static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf, + bool flush) { if (sc->rx.buf_hold) - ath_rx_buf_link(sc, sc->rx.buf_hold); + ath_rx_buf_link(sc, sc->rx.buf_hold, flush); sc->rx.buf_hold = bf; } @@ -442,7 +444,7 @@ int ath_startrecv(struct ath_softc *sc) sc->rx.buf_hold = NULL; sc->rx.rxlink = NULL; list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { - ath_rx_buf_link(sc, bf); + ath_rx_buf_link(sc, bf, false); } /* We could have deleted elements so the list may be empty now */ @@ -538,7 +540,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); - ath9k_set_beacon(sc); + if (!(WARN_ON_ONCE(sc->cur_beacon_conf.beacon_interval == 0))) + ath9k_set_beacon(sc); + if (sc->p2p_ps_vif) + ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); } if (ath_beacon_dtim_pending_cab(skb)) { @@ -762,204 +767,6 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc, return bf; } -/* Assumes you've already done the endian to CPU conversion */ -static bool ath9k_rx_accept(struct ath_common *common, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *rxs, - struct ath_rx_status *rx_stats, - bool *decrypt_error) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - bool is_mc, is_valid_tkip, strip_mic, mic_error; - struct ath_hw *ah = common->ah; - __le16 fc; - - fc = hdr->frame_control; - - is_mc = !!is_multicast_ether_addr(hdr->addr1); - is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && - test_bit(rx_stats->rs_keyix, common->tkip_keymap); - strip_mic = is_valid_tkip && ieee80211_is_data(fc) && - ieee80211_has_protected(fc) && - !(rx_stats->rs_status & - (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | - ATH9K_RXERR_KEYMISS)); - - /* - * Key miss events are only relevant for pairwise keys where the - * descriptor does contain a valid key index. This has been observed - * mostly with CCMP encryption. - */ - if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || - !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) - rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; - - mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && - !ieee80211_has_morefrags(fc) && - !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && - (rx_stats->rs_status & ATH9K_RXERR_MIC); - - /* - * The rx_stats->rs_status will not be set until the end of the - * chained descriptors so it can be ignored if rs_more is set. The - * rs_more will be false at the last element of the chained - * descriptors. - */ - if (rx_stats->rs_status != 0) { - u8 status_mask; - - if (rx_stats->rs_status & ATH9K_RXERR_CRC) { - rxs->flag |= RX_FLAG_FAILED_FCS_CRC; - mic_error = false; - } - - if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || - (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { - *decrypt_error = true; - mic_error = false; - } - - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_KEYMISS; - - if (ah->is_monitoring && (sc->rx.rxfilter & FIF_FCSFAIL)) - status_mask |= ATH9K_RXERR_CRC; - - if (rx_stats->rs_status & ~status_mask) - return false; - } - - /* - * For unicast frames the MIC error bit can have false positives, - * so all MIC error reports need to be validated in software. - * False negatives are not common, so skip software verification - * if the hardware considers the MIC valid. - */ - if (strip_mic) - rxs->flag |= RX_FLAG_MMIC_STRIPPED; - else if (is_mc && mic_error) - rxs->flag |= RX_FLAG_MMIC_ERROR; - - return true; -} - -static int ath9k_process_rate(struct ath_common *common, - struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs) -{ - struct ieee80211_supported_band *sband; - enum ieee80211_band band; - unsigned int i = 0; - struct ath_softc __maybe_unused *sc = common->priv; - struct ath_hw *ah = sc->sc_ah; - - band = ah->curchan->chan->band; - sband = hw->wiphy->bands[band]; - - if (IS_CHAN_QUARTER_RATE(ah->curchan)) - rxs->flag |= RX_FLAG_5MHZ; - else if (IS_CHAN_HALF_RATE(ah->curchan)) - rxs->flag |= RX_FLAG_10MHZ; - - if (rx_stats->rs_rate & 0x80) { - /* HT rate */ - rxs->flag |= RX_FLAG_HT; - rxs->flag |= rx_stats->flag; - rxs->rate_idx = rx_stats->rs_rate & 0x7f; - return 0; - } - - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { - rxs->rate_idx = i; - return 0; - } - if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { - rxs->flag |= RX_FLAG_SHORTPRE; - rxs->rate_idx = i; - return 0; - } - } - - /* - * No valid hardware bitrate found -- we should not get here - * because hardware has already validated this frame as OK. - */ - ath_dbg(common, ANY, - "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", - rx_stats->rs_rate); - RX_STAT_INC(rx_rate_err); - return -EINVAL; -} - -static void ath9k_process_rssi(struct ath_common *common, - struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = common->ah; - int last_rssi; - int rssi = rx_stats->rs_rssi; - int i, j; - - /* - * RSSI is not available for subframes in an A-MPDU. - */ - if (rx_stats->rs_moreaggr) { - rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; - return; - } - - /* - * Check if the RSSI for the last subframe in an A-MPDU - * or an unaggregated frame is valid. - */ - if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { - rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; - return; - } - - for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { - s8 rssi; - - if (!(ah->rxchainmask & BIT(i))) - continue; - - rssi = rx_stats->rs_rssi_ctl[i]; - if (rssi != ATH9K_RSSI_BAD) { - rxs->chains |= BIT(j); - rxs->chain_signal[j] = ah->noise + rssi; - } - j++; - } - - /* - * Update Beacon RSSI, this is used by ANI. - */ - if (rx_stats->is_mybeacon && - ((ah->opmode == NL80211_IFTYPE_STATION) || - (ah->opmode == NL80211_IFTYPE_ADHOC))) { - ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); - last_rssi = sc->last_rssi; - - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); - if (rssi < 0) - rssi = 0; - - ah->stats.avgbrssi = rssi; - } - - rxs->signal = ah->noise + rx_stats->rs_rssi; -} - static void ath9k_process_tsf(struct ath_rx_status *rs, struct ieee80211_rx_status *rxs, u64 tsf) @@ -1055,7 +862,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. */ - if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) return -EINVAL; if (ath_is_mybeacon(common, hdr)) { @@ -1069,10 +876,18 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (WARN_ON(!ah->curchan)) return -EINVAL; - if (ath9k_process_rate(common, hw, rx_stats, rx_status)) + if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { + /* + * No valid hardware bitrate found -- we should not get here + * because hardware has already validated this frame as OK. + */ + ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", + rx_stats->rs_rate); + RX_STAT_INC(rx_rate_err); return -EINVAL; + } - ath9k_process_rssi(common, hw, rx_stats, rx_status); + ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); rx_status->band = ah->curchan->chan->band; rx_status->freq = ah->curchan->chan->center_freq; @@ -1092,57 +907,6 @@ corrupt: return -EINVAL; } -static void ath9k_rx_skb_postprocess(struct ath_common *common, - struct sk_buff *skb, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs, - bool decrypt_error) -{ - struct ath_hw *ah = common->ah; - struct ieee80211_hdr *hdr; - int hdrlen, padpos, padsize; - u8 keyix; - __le16 fc; - - /* see if any padding is done by the hw and remove it */ - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - padpos = ieee80211_hdrlen(fc); - - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - padpos % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - padsize = padpos & 3; - if (padsize && skb->len>=padpos+padsize+FCS_LEN) { - memmove(skb->data + padsize, skb->data, padpos); - skb_pull(skb, padsize); - } - - keyix = rx_stats->rs_keyix; - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && - ieee80211_has_protected(fc)) { - rxs->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) - && !decrypt_error && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, common->keymap)) - rxs->flag |= RX_FLAG_DECRYPTED; - } - if (ah->sw_mgmt_crypto && - (rxs->flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(fc)) - /* Use software decrypt for management frames. */ - rxs->flag &= ~RX_FLAG_DECRYPTED; -} - /* * Run the LNA combining algorithm only in these cases: * @@ -1216,6 +980,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) u64 tsf = 0; unsigned long flags; dma_addr_t new_buf_addr; + unsigned int budget = 512; if (edma) dma_type = DMA_BIDIRECTIONAL; @@ -1292,8 +1057,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) skb_pull(skb, ah->caps.rx_status_len); if (!rs.rs_more) - ath9k_rx_skb_postprocess(common, hdr_skb, &rs, - rxs, decrypt_error); + ath9k_cmn_rx_skb_postprocess(common, hdr_skb, &rs, + rxs, decrypt_error); if (rs.rs_more) { RX_STAT_INC(rx_frags); @@ -1354,15 +1119,17 @@ requeue_drop_frag: } requeue: list_add_tail(&bf->list, &sc->rx.rxbuf); - if (flush) - continue; - if (edma) { + if (!edma) { + ath_rx_buf_relink(sc, bf, flush); + if (!flush) + ath9k_hw_rxena(ah); + } else if (!flush) { ath_rx_edma_buf_link(sc, qtype); - } else { - ath_rx_buf_relink(sc, bf); - ath9k_hw_rxena(ah); } + + if (!budget--) + break; } while (1); if (!(ah->imask & ATH9K_INT_RXEOL)) { diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index b1fd3fa8498..f1bbce3f777 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -505,9 +505,6 @@ #define AR_D_QCUMASK 0x000003FF #define AR_D_QCUMASK_RESV0 0xFFFFFC00 -#define AR_D_TXBLK_CMD 0x1038 -#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) - #define AR_D0_LCL_IFS 0x1040 #define AR_D1_LCL_IFS 0x1044 #define AR_D2_LCL_IFS 0x1048 diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index b686a749845..a65cfb91adc 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -108,7 +108,7 @@ static int ath9k_tx99_init(struct ath_softc *sc) struct ath_tx_control txctl; int r; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_err(common, "driver is in invalid state unable to use TX99"); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1b3230fa365..2879887f569 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -198,7 +198,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath_cancel_work(sc); ath_stop_ani(sc); - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); ret = -EINVAL; goto fail_wow; @@ -224,7 +224,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, * STA. */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ath_dbg(common, WOW, "None of the STA vifs are associated\n"); ret = 1; goto fail_wow; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 55897d508a7..7c28cb55610 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -107,9 +107,6 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) { struct ath_atx_ac *ac = tid->ac; - if (tid->paused) - return; - if (tid->sched) return; @@ -890,6 +887,15 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, tx_info = IEEE80211_SKB_CB(skb); tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; + + /* + * No aggregation session is running, but there may be frames + * from a previous session or a failed attempt in the queue. + * Send them out as normal data frames + */ + if (!tid->active) + tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; + if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { bf->bf_state.bf_type = 0; return bf; @@ -1040,11 +1046,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi) int symbols, bits; int bytes = 0; + usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec); bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; bits -= OFDM_PLCP_BITS; bytes = bits / 8; - bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); if (bytes > 65532) bytes = 65532; @@ -1076,6 +1082,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_info *info, int len, bool rts) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -1145,7 +1152,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, } /* legacy rates */ - rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; + rate = &common->sbands[tx_info->band].bitrates[rates[i].idx]; if ((tx_info->band == IEEE80211_BAND_2GHZ) && !(rate->flags & IEEE80211_RATE_ERP_G)) phy = WLAN_RC_PHY_CCK; @@ -1406,7 +1413,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, ath_tx_tid_change_state(sc, txtid); txtid->active = true; - txtid->paused = true; *ssn = txtid->seq_start = txtid->seq_next; txtid->bar_index = -1; @@ -1426,7 +1432,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) ath_txq_lock(sc, txq); txtid->active = false; - txtid->paused = false; ath_tx_flush_tid(sc, txtid); ath_tx_tid_change_state(sc, txtid); ath_txq_unlock_complete(sc, txq); @@ -1486,7 +1491,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) ath_txq_lock(sc, txq); ac->clear_ps_filter = true; - if (!tid->paused && ath_tid_has_buffered(tid)) { + if (ath_tid_has_buffered(tid)) { ath_tx_queue_tid(txq, tid); ath_txq_schedule(sc, txq); } @@ -1509,7 +1514,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, ath_txq_lock(sc, txq); tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; - tid->paused = false; if (ath_tid_has_buffered(tid)) { ath_tx_queue_tid(txq, tid); @@ -1543,8 +1547,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, continue; tid = ATH_AN_2_TID(an, i); - if (tid->paused) - continue; ath_txq_lock(sc, tid->ac->txq); while (nframes > 0) { @@ -1698,7 +1700,7 @@ int ath_cabq_update(struct ath_softc *sc) ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); - qi.tqi_readyTime = (cur_conf->beacon_interval * + qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) * ATH_CABQ_READY_TIME) / 100; ath_txq_update(sc, qnum, &qi); @@ -1768,7 +1770,7 @@ bool ath_drain_all_txq(struct ath_softc *sc) int i; u32 npend = 0; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return true; ath9k_hw_abort_tx_dma(ah); @@ -1816,11 +1818,12 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_ac *ac, *last_ac; struct ath_atx_tid *tid, *last_tid; bool sent = false; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || + if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || list_empty(&txq->axq_acq)) return; @@ -1842,9 +1845,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) list_del(&tid->list); tid->sched = false; - if (tid->paused) - continue; - if (ath_tx_sched_aggr(sc, txq, tid, &stop)) sent = true; @@ -2470,7 +2470,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_lock(sc, txq); for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; if (list_empty(&txq->axq_q)) { @@ -2553,7 +2553,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) int status; for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); @@ -2569,7 +2569,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) sc->beacon.tx_processed = true; sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); - ath9k_csa_is_finished(sc); + ath9k_csa_update(sc); continue; } @@ -2696,7 +2696,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->baw_size = WME_MAX_BA; tid->baw_head = tid->baw_tail = 0; tid->sched = false; - tid->paused = false; tid->active = false; __skb_queue_head_init(&tid->buf_q); __skb_queue_head_init(&tid->retry_q); diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 4c8cdb097b6..f8ded84b7be 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1707,7 +1707,9 @@ found: return 0; } -static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void carl9170_op_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, bool drop) { struct ar9170 *ar = hw->priv; unsigned int vid; diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 536bc46a291..924135b8e57 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -572,7 +572,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) { - struct ieee80211_bar *bar = (void *) data; + struct ieee80211_bar *bar = data; struct carl9170_bar_list_entry *entry; unsigned int queue; diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index ca115f33746..f35c7f30f9a 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -1076,8 +1076,14 @@ static int carl9170_usb_probe(struct usb_interface *intf, carl9170_set_state(ar, CARL9170_STOPPED); - return request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME, + err = request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME, &ar->udev->dev, GFP_KERNEL, ar, carl9170_usb_firmware_step2); + if (err) { + usb_put_dev(udev); + usb_put_dev(udev); + carl9170_free(ar); + } + return err; } static void carl9170_usb_disconnect(struct usb_interface *intf) diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index a1a69c5db40..650be79c7ac 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -73,9 +73,52 @@ static const struct radar_types etsi_radar_types_v15 = { .radar_types = etsi_radar_ref_types_v15, }; -/* for now, we support ETSI radar types, FCC and JP are TODO */ +#define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \ +{ \ + ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \ + PMIN - PRI_TOLERANCE, \ + PMAX * PRF + PRI_TOLERANCE, PRF, PPB * PRF, \ + PPB_THRESH(PPB), PRI_TOLERANCE, \ +} + +static const struct radar_detector_specs fcc_radar_ref_types[] = { + FCC_PATTERN(0, 0, 1, 1428, 1428, 1, 18), + FCC_PATTERN(1, 0, 5, 150, 230, 1, 23), + FCC_PATTERN(2, 6, 10, 200, 500, 1, 16), + FCC_PATTERN(3, 11, 20, 200, 500, 1, 12), + FCC_PATTERN(4, 50, 100, 1000, 2000, 20, 1), + FCC_PATTERN(5, 0, 1, 333, 333, 1, 9), +}; + +static const struct radar_types fcc_radar_types = { + .region = NL80211_DFS_FCC, + .num_radar_types = ARRAY_SIZE(fcc_radar_ref_types), + .radar_types = fcc_radar_ref_types, +}; + +#define JP_PATTERN FCC_PATTERN +static const struct radar_detector_specs jp_radar_ref_types[] = { + JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18), + JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18), + JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18), + JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18), + JP_PATTERN(4, 0, 5, 150, 230, 1, 23), + JP_PATTERN(5, 6, 10, 200, 500, 1, 16), + JP_PATTERN(6, 11, 20, 200, 500, 1, 12), + JP_PATTERN(7, 50, 100, 1000, 2000, 20, 1), + JP_PATTERN(5, 0, 1, 333, 333, 1, 9), +}; + +static const struct radar_types jp_radar_types = { + .region = NL80211_DFS_JP, + .num_radar_types = ARRAY_SIZE(jp_radar_ref_types), + .radar_types = jp_radar_ref_types, +}; + static const struct radar_types *dfs_domains[] = { &etsi_radar_types_v15, + &fcc_radar_types, + &jp_radar_types, }; /** diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index e5e905910db..415393dfb6f 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void) static const struct ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) { - switch (reg->regpair->regDmnEnum) { + switch (reg->regpair->reg_domain) { case 0x60: case 0x61: case 0x62: @@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ath_regulatory *reg) { - switch (reg->regpair->regDmnEnum) { + switch (reg->regpair->reg_domain) { case 0x60: case 0x63: case 0x66: @@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: EEPROM indicates we " "should expect a direct regpair map\n"); for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) + if (regDomainPairs[i].reg_domain == rd) return true; } printk(KERN_DEBUG @@ -617,7 +617,7 @@ ath_get_regpair(int regdmn) if (regdmn == NO_ENUMRD) return NULL; for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regdmn) + if (regDomainPairs[i].reg_domain == regdmn) return ®DomainPairs[i]; } return NULL; @@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", reg->alpha2[0], reg->alpha2[1]); printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", - reg->regpair->regDmnEnum); + reg->regpair->reg_domain); return 0; } diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index ee25786b444..73f12f196f1 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -44,6 +44,14 @@ static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data) writel(data, wcn->mmio + addr); } +#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \ +do { \ + if (wcn->chip_version == WCN36XX_CHIP_3680) \ + wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \ + else \ + wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \ +} while (0) \ + static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data) { *data = readl(wcn->mmio + addr); @@ -680,7 +688,7 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) /* Setting interrupt path */ reg_data = WCN36XX_DXE_CCU_INT; - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data); + wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data); /***************************************/ /* Init descriptors for TX LOW channel */ diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index c88562f85de..35ee7e966bd 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -28,11 +28,11 @@ H2H_TEST_RX_TX = DMA2 */ /* DXE registers */ -#define WCN36XX_DXE_MEM_BASE 0x03000000 #define WCN36XX_DXE_MEM_REG 0x202000 #define WCN36XX_DXE_CCU_INT 0xA0011 -#define WCN36XX_DXE_REG_CCU_INT 0x200b10 +#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10 +#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc /* TODO This must calculated properly but not hardcoded */ #define WCN36XX_DXE_CTRL_TX_L 0x328a44 diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 3c2ef0c32f7..a1f1127d780 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -4384,11 +4384,13 @@ enum place_holder_in_cap_bitmap { MAX_FEATURE_SUPPORTED = 128, }; +#define WCN36XX_HAL_CAPS_SIZE 4 + struct wcn36xx_hal_feat_caps_msg { struct wcn36xx_hal_msg_header header; - u32 feat_caps[4]; + u32 feat_caps[WCN36XX_HAL_CAPS_SIZE]; } __packed; /* status codes to help debug rekey failures */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index e64a6784079..4ab5370ab7a 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -17,6 +17,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> +#include <linux/firmware.h> #include <linux/platform_device.h> #include "wcn36xx.h" @@ -177,6 +178,60 @@ static inline u8 get_sta_index(struct ieee80211_vif *vif, sta_priv->sta_index; } +static const char * const wcn36xx_caps_names[] = { + "MCC", /* 0 */ + "P2P", /* 1 */ + "DOT11AC", /* 2 */ + "SLM_SESSIONIZATION", /* 3 */ + "DOT11AC_OPMODE", /* 4 */ + "SAP32STA", /* 5 */ + "TDLS", /* 6 */ + "P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */ + "WLANACTIVE_OFFLOAD", /* 8 */ + "BEACON_OFFLOAD", /* 9 */ + "SCAN_OFFLOAD", /* 10 */ + "ROAM_OFFLOAD", /* 11 */ + "BCN_MISS_OFFLOAD", /* 12 */ + "STA_POWERSAVE", /* 13 */ + "STA_ADVANCED_PWRSAVE", /* 14 */ + "AP_UAPSD", /* 15 */ + "AP_DFS", /* 16 */ + "BLOCKACK", /* 17 */ + "PHY_ERR", /* 18 */ + "BCN_FILTER", /* 19 */ + "RTT", /* 20 */ + "RATECTRL", /* 21 */ + "WOW" /* 22 */ +}; + +static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x) +{ + if (x >= ARRAY_SIZE(wcn36xx_caps_names)) + return "UNKNOWN"; + return wcn36xx_caps_names[x]; +} + +static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) +{ + int i; + + for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { + if (get_feat_caps(wcn->fw_feat_caps, i)) + wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i)); + } +} + +static void wcn36xx_detect_chip_version(struct wcn36xx *wcn) +{ + if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) { + wcn36xx_info("Chip is 3680\n"); + wcn->chip_version = WCN36XX_CHIP_3680; + } else { + wcn36xx_info("Chip is 3660\n"); + wcn->chip_version = WCN36XX_CHIP_3660; + } +} + static int wcn36xx_start(struct ieee80211_hw *hw) { struct wcn36xx *wcn = hw->priv; @@ -223,6 +278,16 @@ static int wcn36xx_start(struct ieee80211_hw *hw) goto out_free_smd_buf; } + if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { + ret = wcn36xx_smd_feature_caps_exchange(wcn); + if (ret) + wcn36xx_warn("Exchange feature caps failed\n"); + else + wcn36xx_feat_caps_info(wcn); + } + + wcn36xx_detect_chip_version(wcn); + /* DMA channel initialization */ ret = wcn36xx_dxe_init(wcn); if (ret) { @@ -232,11 +297,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw) wcn36xx_debugfs_init(wcn); - if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { - ret = wcn36xx_smd_feature_caps_exchange(wcn); - if (ret) - wcn36xx_warn("Exchange feature caps failed\n"); - } INIT_LIST_HEAD(&wcn->vif_list); return 0; @@ -648,6 +708,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, bss_conf->enable_beacon); if (bss_conf->enable_beacon) { + vif_priv->dtim_period = bss_conf->dtim_period; vif_priv->bss_index = 0xff; wcn36xx_smd_config_bss(wcn, vif, NULL, vif->addr, false); @@ -992,6 +1053,7 @@ static int wcn36xx_remove(struct platform_device *pdev) struct wcn36xx *wcn = hw->priv; wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n"); + release_firmware(wcn->nv); mutex_destroy(&wcn->hal_mutex); ieee80211_unregister_hw(hw); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 750626b0e22..63986931829 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -195,9 +195,11 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn, static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) { int ret = 0; + unsigned long start; wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len); init_completion(&wcn->hal_rsp_compl); + start = jiffies; ret = wcn->ctrl_ops->tx(wcn->hal_buf, len); if (ret) { wcn36xx_err("HAL TX failed\n"); @@ -205,10 +207,13 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) } if (wait_for_completion_timeout(&wcn->hal_rsp_compl, msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) { - wcn36xx_err("Timeout while waiting SMD response\n"); + wcn36xx_err("Timeout! No SMD response in %dms\n", + HAL_MSG_TIMEOUT); ret = -ETIME; goto out; } + wcn36xx_dbg(WCN36XX_DBG_SMD, "SMD command completed in %dms", + jiffies_to_msecs(jiffies - start)); out: return ret; } @@ -246,21 +251,22 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) int wcn36xx_smd_load_nv(struct wcn36xx *wcn) { - const struct firmware *nv; struct nv_data *nv_d; struct wcn36xx_hal_nv_img_download_req_msg msg_body; int fw_bytes_left; int ret; u16 fm_offset = 0; - ret = request_firmware(&nv, WLAN_NV_FILE, wcn->dev); - if (ret) { - wcn36xx_err("Failed to load nv file %s: %d\n", - WLAN_NV_FILE, ret); - goto out_free_nv; + if (!wcn->nv) { + ret = request_firmware(&wcn->nv, WLAN_NV_FILE, wcn->dev); + if (ret) { + wcn36xx_err("Failed to load nv file %s: %d\n", + WLAN_NV_FILE, ret); + goto out; + } } - nv_d = (struct nv_data *)nv->data; + nv_d = (struct nv_data *)wcn->nv->data; INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ); msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE; @@ -270,7 +276,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn) mutex_lock(&wcn->hal_mutex); do { - fw_bytes_left = nv->size - fm_offset - 4; + fw_bytes_left = wcn->nv->size - fm_offset - 4; if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) { msg_body.last_fragment = 0; msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE; @@ -308,10 +314,7 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn) out_unlock: mutex_unlock(&wcn->hal_mutex); -out_free_nv: - release_firmware(nv); - - return ret; +out: return ret; } static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) @@ -899,11 +902,12 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, sta_priv->sta_index = params->sta_index; sta_priv->dpu_desc_index = params->dpu_index; + sta_priv->ucast_dpu_sign = params->uc_ucast_sig; wcn36xx_dbg(WCN36XX_DBG_HAL, - "hal config sta rsp status %d sta_index %d bssid_index %d p2p %d\n", + "hal config sta rsp status %d sta_index %d bssid_index %d uc_ucast_sig %d p2p %d\n", params->status, params->sta_index, params->bssid_index, - params->p2p); + params->uc_ucast_sig, params->p2p); return 0; } @@ -1118,7 +1122,7 @@ static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index; } - priv_vif->ucast_dpu_signature = params->ucast_dpu_signature; + priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature; return 0; } @@ -1637,12 +1641,12 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); if (ret) { - wcn36xx_err("Sending hal_exit_bmps failed\n"); + wcn36xx_err("Sending hal_keep_alive failed\n"); goto out; } ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); if (ret) { - wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret); + wcn36xx_err("hal_keep_alive response failed err=%d\n", ret); goto out; } out: @@ -1682,8 +1686,7 @@ out: return ret; } -static inline void set_feat_caps(u32 *bitmap, - enum place_holder_in_cap_bitmap cap) +void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) { int arr_idx, bit_idx; @@ -1697,8 +1700,7 @@ static inline void set_feat_caps(u32 *bitmap, bitmap[arr_idx] |= (1 << bit_idx); } -static inline int get_feat_caps(u32 *bitmap, - enum place_holder_in_cap_bitmap cap) +int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) { int arr_idx, bit_idx; int ret = 0; @@ -1714,8 +1716,7 @@ static inline int get_feat_caps(u32 *bitmap, return ret; } -static inline void clear_feat_caps(u32 *bitmap, - enum place_holder_in_cap_bitmap cap) +void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap) { int arr_idx, bit_idx; @@ -1731,8 +1732,8 @@ static inline void clear_feat_caps(u32 *bitmap, int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn) { - struct wcn36xx_hal_feat_caps_msg msg_body; - int ret = 0; + struct wcn36xx_hal_feat_caps_msg msg_body, *rsp; + int ret = 0, i; mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ); @@ -1746,12 +1747,15 @@ int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn) wcn36xx_err("Sending hal_feature_caps_exchange failed\n"); goto out; } - ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); - if (ret) { - wcn36xx_err("hal_feature_caps_exchange response failed err=%d\n", - ret); + if (wcn->hal_rsp_len != sizeof(*rsp)) { + wcn36xx_err("Invalid hal_feature_caps_exchange response"); goto out; } + + rsp = (struct wcn36xx_hal_feat_caps_msg *) wcn->hal_buf; + + for (i = 0; i < WCN36XX_HAL_CAPS_SIZE; i++) + wcn->fw_feat_caps[i] = rsp->feat_caps[i]; out: mutex_unlock(&wcn->hal_mutex); return ret; @@ -2064,7 +2068,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) if (!msg_ind) goto nomem; msg_ind->msg_len = len; - msg_ind->msg = kmalloc(len, GFP_KERNEL); + msg_ind->msg = kmemdup(buf, len, GFP_KERNEL); if (!msg_ind->msg) { kfree(msg_ind); nomem: @@ -2076,7 +2080,6 @@ nomem: msg_header->msg_type); break; } - memcpy(msg_ind->msg, buf, len); mutex_lock(&wcn->hal_ind_mutex); list_add_tail(&msg_ind->list, &wcn->hal_ind_queue); queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index e7c39019c6f..008d03423db 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -24,7 +24,7 @@ #define WCN36XX_HAL_BUF_SIZE 4096 -#define HAL_MSG_TIMEOUT 200 +#define HAL_MSG_TIMEOUT 500 #define WCN36XX_SMSM_WLAN_TX_ENABLE 0x00000400 #define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY 0x00000200 /* The PNO version info be contained in the rsp msg */ @@ -112,6 +112,9 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5); int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn); +void set_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); +int get_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); +void clear_feat_caps(u32 *bitmap, enum place_holder_in_cap_bitmap cap); int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index b2b60e30caa..32bb26a0db2 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -57,8 +57,7 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) RX_FLAG_MMIC_STRIPPED | RX_FLAG_DECRYPTED; - wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x status->vendor_radiotap_len=%x\n", - status.flag, status.vendor_radiotap_len); + wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); @@ -132,6 +131,7 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, struct ieee80211_vif, drv_priv); + bd->dpu_sign = sta_priv->ucast_dpu_sign; if (vif->type == NL80211_IFTYPE_STATION) { bd->sta_index = sta_priv->bss_sta_index; bd->dpu_desc_idx = sta_priv->bss_dpu_desc_index; @@ -145,10 +145,9 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, __vif_priv = get_vif_by_addr(wcn, hdr->addr2); bd->sta_index = __vif_priv->self_sta_index; bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index; + bd->dpu_sign = __vif_priv->self_ucast_dpu_sign; } - bd->dpu_sign = __vif_priv->ucast_dpu_signature; - if (ieee80211_is_nullfunc(hdr->frame_control) || (sta_priv && !sta_priv->is_data_encrypted)) bd->dpu_ne = 1; diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 8fa5cbace5a..f0fb81dfd17 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -125,10 +125,10 @@ struct wcn36xx_vif { enum wcn36xx_power_state pw_state; u8 bss_index; - u8 ucast_dpu_signature; /* Returned from WCN36XX_HAL_ADD_STA_SELF_RSP */ u8 self_sta_index; u8 self_dpu_desc_index; + u8 self_ucast_dpu_sign; }; /** @@ -159,6 +159,7 @@ struct wcn36xx_sta { u16 tid; u8 sta_index; u8 dpu_desc_index; + u8 ucast_dpu_sign; u8 bss_sta_index; u8 bss_dpu_desc_index; bool is_data_encrypted; @@ -171,10 +172,14 @@ struct wcn36xx { struct device *dev; struct list_head vif_list; + const struct firmware *nv; + u8 fw_revision; u8 fw_version; u8 fw_minor; u8 fw_major; + u32 fw_feat_caps[WCN36XX_HAL_CAPS_SIZE]; + u32 chip_version; /* extra byte for the NULL termination */ u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; @@ -222,6 +227,9 @@ struct wcn36xx { }; +#define WCN36XX_CHIP_3660 0 +#define WCN36XX_CHIP_3680 1 + static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, u8 major, u8 minor, diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 990dd42ae79..c7a3465fd02 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -9,6 +9,7 @@ wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o +wil6210-y += rx_reorder.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5b340769d5b..820d4ebd932 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } -static int wil_cfg80211_get_station(struct wiphy *wiphy, - struct net_device *ndev, - u8 *mac, struct station_info *sinfo) +static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, + struct station_info *sinfo) { - struct wil6210_priv *wil = wiphy_to_wil(wiphy); - int rc; struct wmi_notify_req_cmd cmd = { - .cid = 0, + .cid = cid, .interval_usec = 0, }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_notify_req_done_event evt; + } __packed reply; + struct wil_net_stats *stats = &wil->sta[cid].stats; + int rc; - if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) - return -ENOENT; - - /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), - WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); + WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; + wil_dbg_wmi(wil, "Link status for CID %d: {\n" + " MCS %d TSF 0x%016llx\n" + " BF status 0x%08x SNR 0x%08x SQI %d%%\n" + " Tx Tpt %d goodput %d Rx goodput %d\n" + " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", + cid, le16_to_cpu(reply.evt.bf_mcs), + le64_to_cpu(reply.evt.tsf), reply.evt.status, + le32_to_cpu(reply.evt.snr_val), + reply.evt.sqi, + le32_to_cpu(reply.evt.tx_tpt), + le32_to_cpu(reply.evt.tx_goodput), + le32_to_cpu(reply.evt.rx_goodput), + le16_to_cpu(reply.evt.my_rx_sector), + le16_to_cpu(reply.evt.my_tx_sector), + le16_to_cpu(reply.evt.other_rx_sector), + le16_to_cpu(reply.evt.other_tx_sector)); + sinfo->generation = wil->sinfo_gen; - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled = STATION_INFO_RX_BYTES | + STATION_INFO_TX_BYTES | + STATION_INFO_RX_PACKETS | + STATION_INFO_TX_PACKETS | + STATION_INFO_RX_BITRATE | + STATION_INFO_TX_BITRATE | + STATION_INFO_RX_DROP_MISC | + STATION_INFO_TX_FAILED; + sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; - sinfo->txrate.mcs = wil->stats.bf_mcs; - sinfo->filled |= STATION_INFO_RX_BITRATE; + sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; - sinfo->rxrate.mcs = wil->stats.last_mcs_rx; + sinfo->rxrate.mcs = stats->last_mcs_rx; + sinfo->rx_bytes = stats->rx_bytes; + sinfo->rx_packets = stats->rx_packets; + sinfo->rx_dropped_misc = stats->rx_dropped; + sinfo->tx_bytes = stats->tx_bytes; + sinfo->tx_packets = stats->tx_packets; + sinfo->tx_failed = stats->tx_errors; if (test_bit(wil_status_fwconnected, &wil->status)) { sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = 12; /* TODO: provide real value */ + sinfo->signal = reply.evt.sqi; } - return 0; + return rc; +} + +static int wil_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, struct station_info *sinfo) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + int cid = wil_find_cid(wil, mac); + + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + if (cid < 0) + return cid; + + rc = wil_cid_fill_sinfo(wil, cid, sinfo); + + return rc; +} + +/* + * Find @idx-th active STA for station dump. + */ +static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if (wil->sta[i].status == wil_sta_unused) + continue; + if (idx == 0) + return i; + idx--; + } + + return -ENOENT; +} + +static int wil_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, int idx, + u8 *mac, struct station_info *sinfo) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + int cid = wil_find_cid_by_idx(wil, idx); + + if (cid < 0) + return -ENOENT; + + memcpy(mac, wil->sta[cid].addr, ETH_ALEN); + wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + + rc = wil_cid_fill_sinfo(wil, cid, sinfo); + + return rc; } static int wil_cfg80211_change_iface(struct wiphy *wiphy, @@ -181,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, u16 chnl[4]; } __packed cmd; uint i, n; + int rc; if (wil->scan_request) { wil_err(wil, "Already scanning\n"); @@ -198,11 +283,12 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, /* FW don't support scan after connection attempt */ if (test_bit(wil_status_dontscan, &wil->status)) { - wil_err(wil, "Scan after connect attempt not supported\n"); + wil_err(wil, "Can't scan now\n"); return -EBUSY; } wil->scan_request = request; + mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); memset(&cmd, 0, sizeof(cmd)); cmd.cmd.num_channels = 0; @@ -221,8 +307,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, request->channels[i]->center_freq); } - return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + + rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); + + if (rc) + wil->scan_request = NULL; + + return rc; } static int wil_cfg80211_connect(struct wiphy *wiphy, @@ -237,6 +328,10 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; + if (test_bit(wil_status_fwconnecting, &wil->status) || + test_bit(wil_status_fwconnected, &wil->status)) + return -EALREADY; + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); @@ -318,10 +413,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); - /* - * FW don't support scan after connection attempt - */ - set_bit(wil_status_dontscan, &wil->status); + set_bit(wil_status_fwconnecting, &wil->status); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); @@ -330,7 +422,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); } else { - clear_bit(wil_status_dontscan, &wil->status); clear_bit(wil_status_fwconnecting, &wil->status); } @@ -352,6 +443,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return rc; } +static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + const u8 *buf = params->buf; + size_t len = params->len; + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + struct ieee80211_mgmt *mgmt_frame = (void *)buf; + struct wmi_sw_tx_req_cmd *cmd; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_sw_tx_complete_event evt; + } __packed evt; + + cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); + cmd->len = cpu_to_le16(len); + memcpy(cmd->payload, buf, len); + + rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, + WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); + if (rc == 0) + rc = evt.evt.status; + + kfree(cmd); + + return rc; +} + static int wil_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { @@ -402,6 +527,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy, return 0; } +static int wil_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + /* TODO: handle duration */ + wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); + + rc = wmi_set_channel(wil, chan->hw_value); + if (rc) + return rc; + + rc = wmi_rxon(wil, true); + + return rc; +} + +static int wil_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + wil_info(wil, "%s()\n", __func__); + + rc = wmi_rxon(wil, false); + + return rc; +} + static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { @@ -450,18 +610,20 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, if (wil_fix_bcon(wil, bcon)) wil_dbg_misc(wil, "Fixed bcon\n"); + mutex_lock(&wil->mutex); + rc = wil_reset(wil); if (rc) - return rc; + goto out; /* Rx VRING. */ rc = wil_rx_init(wil); if (rc) - return rc; + goto out; rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); if (rc) - return rc; + goto out; /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); @@ -485,11 +647,13 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - return rc; + goto out; netif_carrier_on(ndev); +out: + mutex_unlock(&wil->mutex); return rc; } @@ -499,17 +663,36 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, int rc = 0; struct wil6210_priv *wil = wiphy_to_wil(wiphy); + mutex_lock(&wil->mutex); + rc = wmi_pcp_stop(wil); + mutex_unlock(&wil->mutex); return rc; } +static int wil_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, const u8 *mac) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + mutex_lock(&wil->mutex); + wil6210_disconnect(wil, mac); + mutex_unlock(&wil->mutex); + + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, .disconnect = wil_cfg80211_disconnect, .change_virtual_intf = wil_cfg80211_change_iface, .get_station = wil_cfg80211_get_station, + .dump_station = wil_cfg80211_dump_station, + .remain_on_channel = wil_remain_on_channel, + .cancel_remain_on_channel = wil_cancel_remain_on_channel, + .mgmt_tx = wil_cfg80211_mgmt_tx, .set_monitor_channel = wil_cfg80211_set_channel, .add_key = wil_cfg80211_add_key, .del_key = wil_cfg80211_del_key, @@ -517,6 +700,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { /* AP mode */ .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, + .del_station = wil_cfg80211_del_station, }; static void wil_wiphy_init(struct wiphy *wiphy) @@ -542,7 +726,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; /* TODO: figure this out */ - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 1caa31992a7..8d4bc4bfb66 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -26,14 +26,16 @@ /* Nasty hack. Better have per device instances */ static u32 mem_addr; static u32 dbg_txdesc_index; +static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, - const char *name, struct vring *vring) + const char *name, struct vring *vring, + char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); seq_printf(s, "VRING %s = {\n", name); - seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa); + seq_printf(s, " pa = %pad\n", &vring->pa); seq_printf(s, " va = 0x%p\n", vring->va); seq_printf(s, " size = %d\n", vring->size); seq_printf(s, " swtail = %d\n", vring->swtail); @@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, volatile struct vring_tx_desc *d = &vring->va[i].tx; if ((i % 64) == 0 && (i != 0)) seq_printf(s, "\n"); - seq_printf(s, "%s", (d->dma.status & BIT(0)) ? - "S" : (vring->ctx[i].skb ? "H" : "h")); + seq_printf(s, "%c", (d->dma.status & BIT(0)) ? + _s : (vring->ctx[i].skb ? _h : 'h')); } seq_printf(s, "\n"); } @@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) uint i; struct wil6210_priv *wil = s->private; - wil_print_vring(s, wil, "rx", &wil->vring_rx); + wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); if (vring->va) { + int cid = wil->vring2cid_tid[i][0]; + int tid = wil->vring2cid_tid[i][1]; char name[10]; snprintf(name, sizeof(name), "tx_%2d", i); - wil_print_vring(s, wil, name, vring); + + seq_printf(s, "\n%pM CID %d TID %d\n", + wil->sta[cid].addr, cid, tid); + wil_print_vring(s, wil, name, vring, '_', 'H'); } } @@ -390,57 +397,98 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; -/*---------Tx descriptor------------*/ +static void wil_seq_hexdump(struct seq_file *s, void *p, int len, + const char *prefix) +{ + char printbuf[16 * 3 + 2]; + int i = 0; + while (i < len) { + int l = min(len - i, 16); + hex_dump_to_buffer(p + i, l, 16, 1, printbuf, + sizeof(printbuf), false); + seq_printf(s, "%s%s\n", prefix, printbuf); + i += l; + } +} + +static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) +{ + int i = 0; + int len = skb_headlen(skb); + void *p = skb->data; + int nr_frags = skb_shinfo(skb)->nr_frags; + + seq_printf(s, " len = %d\n", len); + wil_seq_hexdump(s, p, len, " : "); + + if (nr_frags) { + seq_printf(s, " nr_frags = %d\n", nr_frags); + for (i = 0; i < nr_frags; i++) { + const struct skb_frag_struct *frag = + &skb_shinfo(skb)->frags[i]; + + len = skb_frag_size(frag); + p = skb_frag_address_safe(frag); + seq_printf(s, " [%2d] : len = %d\n", i, len); + wil_seq_hexdump(s, p, len, " : "); + } + } +} + +/*---------Tx/Rx descriptor------------*/ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - struct vring *vring = &(wil->vring_tx[0]); + struct vring *vring; + bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); + if (tx) + vring = &(wil->vring_tx[dbg_vring_index]); + else + vring = &wil->vring_rx; if (!vring->va) { - seq_printf(s, "No Tx VRING\n"); + if (tx) + seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); + else + seq_puts(s, "No Rx VRING\n"); return 0; } if (dbg_txdesc_index < vring->size) { + /* use struct vring_tx_desc for Rx as well, + * only field used, .dma.length, is the same + */ volatile struct vring_tx_desc *d = &(vring->va[dbg_txdesc_index].tx); volatile u32 *u = (volatile u32 *)d; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; - seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); + if (tx) + seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, + dbg_txdesc_index); + else + seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[0], u[1], u[2], u[3]); seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[4], u[5], u[6], u[7]); - seq_printf(s, " SKB = %p\n", skb); + seq_printf(s, " SKB = 0x%p\n", skb); if (skb) { - char printbuf[16 * 3 + 2]; - int i = 0; - int len = le16_to_cpu(d->dma.length); - void *p = skb->data; - - if (len != skb_headlen(skb)) { - seq_printf(s, "!!! len: desc = %d skb = %d\n", - len, skb_headlen(skb)); - len = min_t(int, len, skb_headlen(skb)); - } - - seq_printf(s, " len = %d\n", len); - - while (i < len) { - int l = min(len - i, 16); - hex_dump_to_buffer(p + i, l, 16, 1, printbuf, - sizeof(printbuf), false); - seq_printf(s, " : %s\n", printbuf); - i += l; - } + skb_get(skb); + wil_seq_print_skb(s, skb); + kfree_skb(skb); } seq_printf(s, "}\n"); } else { - seq_printf(s, "TxDesc index (%d) >= size (%d)\n", - dbg_txdesc_index, vring->size); + if (tx) + seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", + dbg_vring_index, dbg_txdesc_index, + vring->size); + else + seq_printf(s, "RxDesc index (%d) >= size (%d)\n", + dbg_txdesc_index, vring->size); } return 0; @@ -570,6 +618,69 @@ static const struct file_operations fops_temp = { .llseek = seq_lseek, }; +/*---------Station matrix------------*/ +static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) +{ + int i; + u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; + seq_printf(s, "0x%03x [", r->head_seq_num); + for (i = 0; i < r->buf_size; i++) { + if (i == index) + seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); + else + seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); + } + seq_puts(s, "]\n"); +} + +static int wil_sta_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + int i, tid; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *p = &wil->sta[i]; + char *status = "unknown"; + switch (p->status) { + case wil_sta_unused: + status = "unused "; + break; + case wil_sta_conn_pending: + status = "pending "; + break; + case wil_sta_connected: + status = "connected"; + break; + } + seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, + (p->data_port_open ? " data_port_open" : "")); + + if (p->status == wil_sta_connected) { + for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { + struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; + if (r) { + seq_printf(s, "[%2d] ", tid); + wil_print_rxtid(s, r); + } + } + } + } + + return 0; +} + +static int wil_sta_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_sta_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_sta = { + .open = wil_sta_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*----------------*/ int wil6210_debugfs_init(struct wil6210_priv *wil) { @@ -581,9 +692,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); - debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); - debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, + debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta); + debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); + debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, &dbg_txdesc_index); + debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg, + &dbg_vring_index); + debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 10919f95a83..73593aa3cd9 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -195,8 +195,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { wil_dbg_irq(wil, "RX done\n"); isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; - wil_dbg_txrx(wil, "NAPI schedule\n"); - napi_schedule(&wil->napi_rx); + if (test_bit(wil_status_reset_done, &wil->status)) { + wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); + napi_schedule(&wil->napi_rx); + } else { + wil_err(wil, "Got Rx interrupt while in reset\n"); + } } if (isr) @@ -226,10 +230,15 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { wil_dbg_irq(wil, "TX done\n"); - napi_schedule(&wil->napi_tx); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); + if (test_bit(wil_status_reset_done, &wil->status)) { + wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); + napi_schedule(&wil->napi_tx); + } else { + wil_err(wil, "Got Tx interrupt while in reset\n"); + } } if (isr) @@ -319,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) if (isr & ISR_MISC_FW_ERROR) { wil_notify_fw_error(wil); isr &= ~ISR_MISC_FW_ERROR; + wil_fw_error_recovery(wil); } if (isr & ISR_MISC_MBOX_EVT) { @@ -328,7 +338,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) } if (isr) - wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); + wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr); wil->isr_misc = 0; @@ -493,6 +503,23 @@ free0: return rc; } +/* can't use wil_ioread32_and_clear because ICC value is not ser yet */ +static inline void wil_clear32(void __iomem *addr) +{ + u32 x = ioread32(addr); + + iowrite32(x, addr); +} + +void wil6210_clear_irq(struct wil6210_priv *wil) +{ + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + + offsetof(struct RGF_ICR, ICR)); +} int wil6210_init_irq(struct wil6210_priv *wil, int irq) { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index fd30cddd588..11e6d9d22ea 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -16,8 +16,14 @@ #include <linux/moduleparam.h> #include <linux/if_arp.h> +#include <linux/etherdevice.h> #include "wil6210.h" +#include "txrx.h" + +static bool no_fw_recovery; +module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery"); /* * Due to a hardware issue, @@ -52,29 +58,74 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, __raw_writel(*s++, d++); } -static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) +static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) { uint i; - struct net_device *ndev = wil_to_ndev(wil); + struct wil_sta_info *sta = &wil->sta[cid]; - wil_dbg_misc(wil, "%s()\n", __func__); + sta->data_port_open = false; + if (sta->status != wil_sta_unused) { + wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); + sta->status = wil_sta_unused; + } - wil_link_off(wil); - if (test_bit(wil_status_fwconnected, &wil->status)) { - clear_bit(wil_status_fwconnected, &wil->status); - cfg80211_disconnected(ndev, - WLAN_STATUS_UNSPECIFIED_FAILURE, - NULL, 0, GFP_KERNEL); - } else if (test_bit(wil_status_fwconnecting, &wil->status)) { - cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + } + for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { + if (wil->vring2cid_tid[i][0] == cid) + wil_vring_fini_tx(wil, i); } - clear_bit(wil_status_fwconnecting, &wil->status); - for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) - wil_vring_fini_tx(wil, i); + memset(&sta->stats, 0, sizeof(sta->stats)); +} - clear_bit(wil_status_dontscan, &wil->status); +static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) +{ + int cid = -ENOENT; + struct net_device *ndev = wil_to_ndev(wil); + struct wireless_dev *wdev = wil->wdev; + + might_sleep(); + if (bssid) { + cid = wil_find_cid(wil, bssid); + wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid); + } else { + wil_dbg_misc(wil, "%s(all)\n", __func__); + } + + if (cid >= 0) /* disconnect 1 peer */ + wil_disconnect_cid(wil, cid); + else /* disconnect all */ + for (cid = 0; cid < WIL6210_MAX_CID; cid++) + wil_disconnect_cid(wil, cid); + + /* link state */ + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + wil_link_off(wil); + if (test_bit(wil_status_fwconnected, &wil->status)) { + clear_bit(wil_status_fwconnected, &wil->status); + cfg80211_disconnected(ndev, + WLAN_STATUS_UNSPECIFIED_FAILURE, + NULL, 0, GFP_KERNEL); + } else if (test_bit(wil_status_fwconnecting, &wil->status)) { + cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } + clear_bit(wil_status_fwconnecting, &wil->status); + break; + default: + /* AP-like interface and monitor: + * never scan, always connected + */ + if (bssid) + cfg80211_del_sta(ndev, bssid, GFP_KERNEL); + break; + } } static void wil_disconnect_worker(struct work_struct *work) @@ -82,7 +133,9 @@ static void wil_disconnect_worker(struct work_struct *work) struct wil6210_priv *wil = container_of(work, struct wil6210_priv, disconnect_worker); + mutex_lock(&wil->mutex); _wil6210_disconnect(wil, NULL); + mutex_unlock(&wil->mutex); } static void wil_connect_timer_fn(ulong x) @@ -97,12 +150,82 @@ static void wil_connect_timer_fn(ulong x) schedule_work(&wil->disconnect_worker); } +static void wil_scan_timer_fn(ulong x) +{ + struct wil6210_priv *wil = (void *)x; + + clear_bit(wil_status_fwready, &wil->status); + wil_err(wil, "Scan timeout detected, start fw error recovery\n"); + schedule_work(&wil->fw_error_worker); +} + +static void wil_fw_error_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, + struct wil6210_priv, fw_error_worker); + struct wireless_dev *wdev = wil->wdev; + + wil_dbg_misc(wil, "fw error worker\n"); + + if (no_fw_recovery) + return; + + /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO + * passed since last recovery attempt + */ + if (time_is_after_jiffies(wil->last_fw_recovery + + WIL6210_FW_RECOVERY_TO)) + wil->recovery_count++; + else + wil->recovery_count = 1; /* fw was alive for a long time */ + + if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) { + wil_err(wil, "too many recovery attempts (%d), giving up\n", + wil->recovery_count); + return; + } + + wil->last_fw_recovery = jiffies; + + mutex_lock(&wil->mutex); + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_MONITOR: + wil_info(wil, "fw error recovery started (try %d)...\n", + wil->recovery_count); + wil_reset(wil); + + /* need to re-allocate Rx ring after reset */ + wil_rx_init(wil); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + /* recovery in these modes is done by upper layers */ + break; + default: + break; + } + mutex_unlock(&wil->mutex); +} + +static int wil_find_free_vring(struct wil6210_priv *wil) +{ + int i; + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + if (!wil->vring_tx[i].va) + return i; + } + return -EINVAL; +} + static void wil_connect_worker(struct work_struct *work) { int rc; struct wil6210_priv *wil = container_of(work, struct wil6210_priv, connect_worker); int cid = wil->pending_connect_cid; + int ringid = wil_find_free_vring(wil); if (cid < 0) { wil_err(wil, "No connection pending\n"); @@ -111,16 +234,22 @@ static void wil_connect_worker(struct work_struct *work) wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); - rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0); + rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0); wil->pending_connect_cid = -1; - if (rc == 0) + if (rc == 0) { + wil->sta[cid].status = wil_sta_connected; wil_link_on(wil); + } else { + wil->sta[cid].status = wil_sta_unused; + } } int wil_priv_init(struct wil6210_priv *wil) { wil_dbg_misc(wil, "%s()\n", __func__); + memset(wil->sta, 0, sizeof(wil->sta)); + mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); @@ -128,10 +257,12 @@ int wil_priv_init(struct wil6210_priv *wil) wil->pending_connect_cid = -1; setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); + setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); INIT_WORK(&wil->connect_worker, wil_connect_worker); INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); + INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); @@ -146,10 +277,12 @@ int wil_priv_init(struct wil6210_priv *wil) return -EAGAIN; } + wil->last_fw_recovery = jiffies; + return 0; } -void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) +void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) { del_timer_sync(&wil->connect_timer); _wil6210_disconnect(wil, bssid); @@ -157,8 +290,12 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) void wil_priv_deinit(struct wil6210_priv *wil) { + del_timer_sync(&wil->scan_timer); cancel_work_sync(&wil->disconnect_worker); + cancel_work_sync(&wil->fw_error_worker); + mutex_lock(&wil->mutex); wil6210_disconnect(wil, NULL); + mutex_unlock(&wil->mutex); wmi_event_flush(wil); destroy_workqueue(wil->wmi_wq_conn); destroy_workqueue(wil->wmi_wq); @@ -166,40 +303,78 @@ void wil_priv_deinit(struct wil6210_priv *wil) static void wil_target_reset(struct wil6210_priv *wil) { + int delay = 0; + u32 hw_state; + u32 rev_id; + wil_dbg_misc(wil, "Resetting...\n"); + /* register read */ +#define R(a) ioread32(wil->csr + HOSTADDR(a)) /* register write */ #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) /* register set = read, OR, write */ -#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ - wil->csr + HOSTADDR(a)) +#define S(a, v) W(a, R(a) | v) + /* register clear = read, AND with inverted, write */ +#define C(a, v) W(a, R(a) & ~v) + wil->hw_version = R(RGF_USER_FW_REV_ID); + rev_id = wil->hw_version & 0xff; /* hpal_perst_from_pad_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); /* car_perst_rst_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); + wmb(); /* order is important here */ W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); + if (rev_id == 1) { + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); + } else { + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); + } W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wmb(); /* order is important here */ - wil_dbg_misc(wil, "Reset completed\n"); + /* wait until device ready */ + do { + msleep(1); + hw_state = R(RGF_USER_HW_MACHINE_STATE); + if (delay++ > 100) { + wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + hw_state); + return; + } + } while (hw_state != HW_MACHINE_BOOT_DONE); + if (rev_id == 2) + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wmb(); /* order is important here */ + + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay); + +#undef R #undef W #undef S +#undef C } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) @@ -219,8 +394,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) wil_err(wil, "Firmware not ready\n"); return -ETIME; } else { - wil_dbg_misc(wil, "FW ready after %d ms\n", - jiffies_to_msecs(to-left)); + wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n", + jiffies_to_msecs(to-left), wil->hw_version); } return 0; } @@ -234,11 +409,25 @@ int wil_reset(struct wil6210_priv *wil) { int rc; + WARN_ON(!mutex_is_locked(&wil->mutex)); + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); + wil->status = 0; /* prevent NAPI from being scheduled */ + if (test_bit(wil_status_napi_en, &wil->status)) { + napi_synchronize(&wil->napi_rx); + } + + if (wil->scan_request) { + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", + wil->scan_request); + del_timer_sync(&wil->scan_timer); + cfg80211_scan_done(wil->scan_request, true); + wil->scan_request = NULL; + } + wil6210_disable_irq(wil); - wil->status = 0; wmi_event_flush(wil); @@ -248,6 +437,8 @@ int wil_reset(struct wil6210_priv *wil) /* TODO: put MAC in reset */ wil_target_reset(wil); + wil_rx_fini(wil); + /* init after reset */ wil->pending_connect_cid = -1; reinit_completion(&wil->wmi_ready); @@ -261,6 +452,11 @@ int wil_reset(struct wil6210_priv *wil) return rc; } +void wil_fw_error_recovery(struct wil6210_priv *wil) +{ + wil_dbg_misc(wil, "starting fw error recovery\n"); + schedule_work(&wil->fw_error_worker); +} void wil_link_on(struct wil6210_priv *wil) { @@ -288,6 +484,8 @@ static int __wil_up(struct wil6210_priv *wil) struct wireless_dev *wdev = wil->wdev; int rc; + WARN_ON(!mutex_is_locked(&wil->mutex)); + rc = wil_reset(wil); if (rc) return rc; @@ -329,6 +527,7 @@ static int __wil_up(struct wil6210_priv *wil) napi_enable(&wil->napi_rx); napi_enable(&wil->napi_tx); + set_bit(wil_status_napi_en, &wil->status); return 0; } @@ -346,10 +545,14 @@ int wil_up(struct wil6210_priv *wil) static int __wil_down(struct wil6210_priv *wil) { + WARN_ON(!mutex_is_locked(&wil->mutex)); + + clear_bit(wil_status_napi_en, &wil->status); napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); if (wil->scan_request) { + del_timer_sync(&wil->scan_timer); cfg80211_scan_done(wil->scan_request, true); wil->scan_request = NULL; } @@ -370,3 +573,19 @@ int wil_down(struct wil6210_priv *wil) return rc; } + +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac) +{ + int i; + int rc = -ENOENT; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if ((wil->sta[i].status != wil_sta_unused) && + ether_addr_equal(wil->sta[i].addr, mac)) { + rc = i; + break; + } + } + + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 717178f09aa..106b6dcb773 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -32,12 +32,26 @@ static int wil_stop(struct net_device *ndev) return wil_down(wil); } +static int wil_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct wil6210_priv *wil = ndev_to_wil(ndev); + + if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG) + return -EINVAL; + + wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu); + ndev->mtu = new_mtu; + + return 0; +} + 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_change_mtu = wil_change_mtu, }; static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) @@ -127,8 +141,9 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ndev->netdev_ops = &wil_netdev_ops; ndev->ieee80211_ptr = wdev; - ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; - ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | + NETIF_F_SG | NETIF_F_GRO; + ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index eeceab39cda..1e2e07b9d13 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -41,36 +41,36 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) switch (use_msi) { case 3: case 1: + wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); + break; case 0: + wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); break; default: - wil_err(wil, "Invalid use_msi=%d, default to 1\n", - use_msi); + wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); use_msi = 1; } - wil->n_msi = use_msi; - if (wil->n_msi) { - wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); - rc = pci_enable_msi_block(pdev, wil->n_msi); - if (rc && (wil->n_msi == 3)) { - wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); - wil->n_msi = 1; - rc = pci_enable_msi_block(pdev, wil->n_msi); - } - if (rc) { - wil_err(wil, "pci_enable_msi failed, use INTx\n"); - wil->n_msi = 0; - } - } else { - wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); + + if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { + wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); + use_msi = 1; + } + + if (use_msi == 1 && pci_enable_msi(pdev)) { + wil_err(wil, "pci_enable_msi failed, use INTx\n"); + use_msi = 0; } + wil->n_msi = use_msi; + rc = wil6210_init_irq(wil, pdev->irq); if (rc) goto stop_master; /* need reset here to obtain MAC */ + mutex_lock(&wil->mutex); rc = wil_reset(wil); + mutex_unlock(&wil->mutex); if (rc) goto release_irq; @@ -138,7 +138,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_release_reg; } /* rollback to err_iounmap */ - dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr); + dev_info(&pdev->dev, "CSR at %pR -> 0x%p\n", &pdev->resource[0], csr); wil = wil_if_alloc(dev, csr); if (IS_ERR(wil)) { @@ -151,6 +151,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, wil); wil->pdev = pdev; + wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c new file mode 100644 index 00000000000..747ae127587 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -0,0 +1,201 @@ +#include "wil6210.h" +#include "txrx.h" + +#define SEQ_MODULO 0x1000 +#define SEQ_MASK 0xfff + +static inline int seq_less(u16 sq1, u16 sq2) +{ + return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); +} + +static inline u16 seq_inc(u16 sq) +{ + return (sq + 1) & SEQ_MASK; +} + +static inline u16 seq_sub(u16 sq1, u16 sq2) +{ + return (sq1 - sq2) & SEQ_MASK; +} + +static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) +{ + return seq_sub(seq, r->ssn) % r->buf_size; +} + +static void wil_release_reorder_frame(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r, + int index) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct sk_buff *skb = r->reorder_buf[index]; + + if (!skb) + goto no_frame; + + /* release the frame from the reorder ring buffer */ + r->stored_mpdu_num--; + r->reorder_buf[index] = NULL; + wil_netif_rx_any(skb, ndev); + +no_frame: + r->head_seq_num = seq_inc(r->head_seq_num); +} + +static void wil_release_reorder_frames(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r, + u16 hseq) +{ + int index; + + /* note: this function is never called with + * hseq preceding r->head_seq_num, i.e it is always true + * !seq_less(hseq, r->head_seq_num) + * and thus on loop exit it should be + * r->head_seq_num == hseq + */ + while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) { + index = reorder_index(r, r->head_seq_num); + wil_release_reorder_frame(wil, r, index); + } + r->head_seq_num = hseq; +} + +static void wil_reorder_release(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r) +{ + int index = reorder_index(r, r->head_seq_num); + + while (r->reorder_buf[index]) { + wil_release_reorder_frame(wil, r, index); + index = reorder_index(r, r->head_seq_num); + } +} + +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + int tid = wil_rxdesc_tid(d); + int cid = wil_rxdesc_cid(d); + int mid = wil_rxdesc_mid(d); + u16 seq = wil_rxdesc_seq(d); + struct wil_sta_info *sta = &wil->sta[cid]; + struct wil_tid_ampdu_rx *r = sta->tid_rx[tid]; + u16 hseq; + int index; + + wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", + mid, cid, tid, seq); + + if (!r) { + wil_netif_rx_any(skb, ndev); + return; + } + + hseq = r->head_seq_num; + + spin_lock(&r->reorder_lock); + + /** Due to the race between WMI events, where BACK establishment + * reported, and data Rx, few packets may be pass up before reorder + * buffer get allocated. Catch up by pretending SSN is what we + * see in the 1-st Rx packet + */ + if (r->first_time) { + r->first_time = false; + if (seq != r->head_seq_num) { + wil_err(wil, "Error: 1-st frame with wrong sequence" + " %d, should be %d. Fixing...\n", seq, + r->head_seq_num); + r->head_seq_num = seq; + r->ssn = seq; + } + } + + /* frame with out of date sequence number */ + if (seq_less(seq, r->head_seq_num)) { + dev_kfree_skb(skb); + goto out; + } + + /* + * If frame the sequence number exceeds our buffering window + * size release some previous frames to make room for this one. + */ + if (!seq_less(seq, r->head_seq_num + r->buf_size)) { + hseq = seq_inc(seq_sub(seq, r->buf_size)); + /* release stored frames up to new head to stack */ + wil_release_reorder_frames(wil, r, hseq); + } + + /* Now the new frame is always in the range of the reordering buffer */ + + index = reorder_index(r, seq); + + /* check if we already stored this frame */ + if (r->reorder_buf[index]) { + dev_kfree_skb(skb); + goto out; + } + + /* + * If the current MPDU is in the right order and nothing else + * is stored we can process it directly, no need to buffer it. + * If it is first but there's something stored, we may be able + * to release frames after this one. + */ + if (seq == r->head_seq_num && r->stored_mpdu_num == 0) { + r->head_seq_num = seq_inc(r->head_seq_num); + wil_netif_rx_any(skb, ndev); + goto out; + } + + /* put the frame in the reordering buffer */ + r->reorder_buf[index] = skb; + r->reorder_time[index] = jiffies; + r->stored_mpdu_num++; + wil_reorder_release(wil, r); + +out: + spin_unlock(&r->reorder_lock); +} + +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, + int size, u16 ssn) +{ + struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) + return NULL; + + r->reorder_buf = + kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); + r->reorder_time = + kcalloc(size, sizeof(unsigned long), GFP_KERNEL); + if (!r->reorder_buf || !r->reorder_time) { + kfree(r->reorder_buf); + kfree(r->reorder_time); + kfree(r); + return NULL; + } + + spin_lock_init(&r->reorder_lock); + r->ssn = ssn; + r->head_seq_num = ssn; + r->buf_size = size; + r->stored_mpdu_num = 0; + r->first_time = true; + return r; +} + +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r) +{ + if (!r) + return; + wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size); + kfree(r->reorder_buf); + kfree(r->reorder_time); + kfree(r); +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0b0975d88b4..0784ef3d4ce 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -64,6 +64,22 @@ static inline int wil_vring_avail_tx(struct vring *vring) return vring->size - used - 1; } +/** + * wil_vring_wmark_low - low watermark for available descriptor space + */ +static inline int wil_vring_wmark_low(struct vring *vring) +{ + return vring->size/8; +} + +/** + * wil_vring_wmark_high - high watermark for available descriptor space + */ +static inline int wil_vring_wmark_high(struct vring *vring) +{ + return vring->size/4; +} + static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) { struct device *dev = wil_to_dev(wil); @@ -98,12 +114,29 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) _d->dma.status = TX_DMA_STATUS_DU; } - wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, - vring->va, (unsigned long long)vring->pa, vring->ctx); + wil_dbg_misc(wil, "vring[%d] 0x%p:%pad 0x%p\n", vring->size, + vring->va, &vring->pa, vring->ctx); return 0; } +static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d, + struct wil_ctx *ctx) +{ + dma_addr_t pa = wil_desc_addr(&d->dma.addr); + u16 dmalen = le16_to_cpu(d->dma.length); + switch (ctx->mapped_as) { + case wil_mapped_as_single: + dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + break; + case wil_mapped_as_page: + dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + break; + default: + break; + } +} + static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, int tx) { @@ -122,15 +155,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, ctx = &vring->ctx[vring->swtail]; *d = *_d; - pa = wil_desc_addr(&d->dma.addr); - dmalen = le16_to_cpu(d->dma.length); - if (vring->ctx[vring->swtail].mapped_as_page) { - dma_unmap_page(dev, pa, dmalen, - DMA_TO_DEVICE); - } else { - dma_unmap_single(dev, pa, dmalen, - DMA_TO_DEVICE); - } + wil_txdesc_unmap(dev, d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); vring->swtail = wil_vring_next_tail(vring); @@ -344,6 +369,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, u16 dmalen; u8 ftype; u8 ds_bits; + int cid; + struct wil_net_stats *stats; + BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); @@ -383,8 +411,10 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); - - wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); + cid = wil_rxdesc_cid(d); + stats = &wil->sta[cid].stats; + stats->last_mcs_rx = wil_rxdesc_mcs(d); + wil->stats.last_mcs_rx = stats->last_mcs_rx; /* use radiotap header only if required */ if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) @@ -472,21 +502,28 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) * Pass Rx packet to the netif. Update statistics. * Called in softirq context (NAPI poll). */ -static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { - int rc; + gro_result_t rc; + struct wil6210_priv *wil = ndev_to_wil(ndev); unsigned int len = skb->len; + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + int cid = wil_rxdesc_cid(d); + struct wil_net_stats *stats = &wil->sta[cid].stats; skb_orphan(skb); - rc = netif_receive_skb(skb); + rc = napi_gro_receive(&wil->napi_rx, skb); - if (likely(rc == NET_RX_SUCCESS)) { + if (unlikely(rc == GRO_DROP)) { + ndev->stats.rx_dropped++; + stats->rx_dropped++; + wil_dbg_txrx(wil, "Rx drop %d bytes\n", len); + } else { ndev->stats.rx_packets++; + stats->rx_packets++; ndev->stats.rx_bytes += len; - - } else { - ndev->stats.rx_dropped++; + stats->rx_bytes += len; } } @@ -515,12 +552,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); - + wil_netif_rx_any(skb, ndev); } else { + struct ethhdr *eth = (void *)skb->data; + skb->protocol = eth_type_trans(skb, ndev); + + if (is_unicast_ether_addr(eth->h_dest)) + wil_rx_reorder(wil, skb); + else + wil_netif_rx_any(skb, ndev); } - wil_netif_rx_any(skb, ndev); } wil_rx_refill(wil, v->size); } @@ -530,6 +573,11 @@ int wil_rx_init(struct wil6210_priv *wil) struct vring *vring = &wil->vring_rx; int rc; + if (vring->va) { + wil_err(wil, "Rx ring already allocated\n"); + return -EINVAL; + } + vring->size = WIL6210_RX_RING_SIZE; rc = wil_vring_alloc(wil, vring); if (rc) @@ -570,7 +618,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .ring_size = cpu_to_le16(size), }, .ringid = id, - .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4), + .cidxtid = mk_cidxtid(cid, tid), .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, .mac_ctrl = 0, .to_resolution = 0, @@ -586,6 +634,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, struct wmi_vring_cfg_done_event cmd; } __packed reply; struct vring *vring = &wil->vring_tx[id]; + struct vring_tx_data *txdata = &wil->vring_tx_data[id]; if (vring->va) { wil_err(wil, "Tx ring [%d] already allocated\n", id); @@ -593,11 +642,15 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, goto out; } + memset(txdata, 0, sizeof(*txdata)); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) goto out; + wil->vring2cid_tid[id][0] = cid; + wil->vring2cid_tid[id][1] = tid; + cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), @@ -613,6 +666,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); + txdata->enabled = 1; + return 0; out_free: wil_vring_free(wil, vring, 1); @@ -625,23 +680,116 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) { struct vring *vring = &wil->vring_tx[id]; + WARN_ON(!mutex_is_locked(&wil->mutex)); + if (!vring->va) return; + /* make sure NAPI won't touch this vring */ + wil->vring_tx_data[id].enabled = 0; + if (test_bit(wil_status_napi_en, &wil->status)) + napi_synchronize(&wil->napi_tx); + wil_vring_free(wil, vring, 1); } static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, struct sk_buff *skb) { - struct vring *v = &wil->vring_tx[0]; + int i; + struct ethhdr *eth = (void *)skb->data; + int cid = wil_find_cid(wil, eth->h_dest); + + if (cid < 0) + return NULL; - if (v->va) - return v; + if (!wil->sta[cid].data_port_open && + (skb->protocol != cpu_to_be16(ETH_P_PAE))) + return NULL; + + /* TODO: fix for multiple TID */ + for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { + if (wil->vring2cid_tid[i][0] == cid) { + struct vring *v = &wil->vring_tx[i]; + wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n", + __func__, eth->h_dest, i); + if (v->va) { + return v; + } else { + wil_dbg_txrx(wil, "vring[%d] not valid\n", i); + return NULL; + } + } + } return NULL; } +static void wil_set_da_for_vring(struct wil6210_priv *wil, + struct sk_buff *skb, int vring_index) +{ + struct ethhdr *eth = (void *)skb->data; + int cid = wil->vring2cid_tid[vring_index][0]; + memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN); +} + +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb); +/* + * Find 1-st vring and return it; set dest address for this vring in skb + * duplicate skb and send it to other active vrings + */ +static struct vring *wil_tx_bcast(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct vring *v, *v2; + struct sk_buff *skb2; + int i; + u8 cid; + + /* find 1-st vring eligible for data */ + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + v = &wil->vring_tx[i]; + if (!v->va) + continue; + + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open) + continue; + + goto found; + } + + wil_err(wil, "Tx while no vrings active?\n"); + + return NULL; + +found: + wil_dbg_txrx(wil, "BCAST -> ring %d\n", i); + wil_set_da_for_vring(wil, skb, i); + + /* find other active vrings and duplicate skb for each */ + for (i++; i < WIL6210_MAX_TX_RINGS; i++) { + v2 = &wil->vring_tx[i]; + if (!v2->va) + continue; + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open) + continue; + + skb2 = skb_copy(skb, GFP_ATOMIC); + if (skb2) { + wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); + wil_set_da_for_vring(wil, skb2, i); + wil_tx_vring(wil, v2, skb2); + } else { + wil_err(wil, "skb_copy failed\n"); + } + } + + return v; +} + static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, int vring_index) { @@ -667,6 +815,13 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, return 0; } +static inline +void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags) +{ + d->mac.d[2] |= ((nr_frags + 1) << + MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); +} + static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, struct vring_tx_desc *d, struct sk_buff *skb) @@ -731,8 +886,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "%s()\n", __func__); - if (avail < vring->size/8) - netif_tx_stop_all_queues(wil_to_ndev(wil)); if (avail < 1 + nr_frags) { wil_err(wil, "Tx ring full. No space for %d fragments\n", 1 + nr_frags); @@ -740,19 +893,17 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, } _d = &(vring->va[i].tx); - /* FIXME FW can accept only unicast frames for the peer */ - memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); - pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_txrx(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), - skb->data, (unsigned long long)pa); + wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), + skb->data, &pa); wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); if (unlikely(dma_mapping_error(dev, pa))) return -EINVAL; + vring->ctx[i].mapped_as = wil_mapped_as_single; /* 1-st segment */ wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ @@ -762,8 +913,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, goto dma_error; } - d->mac.d[2] |= ((nr_frags + 1) << - MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); + vring->ctx[i].nr_frags = nr_frags; + wil_tx_desc_set_nr_frags(d, nr_frags); if (nr_frags) *_d = *d; @@ -778,8 +929,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, pa))) goto dma_error; + vring->ctx[i].mapped_as = wil_mapped_as_page; wil_tx_desc_map(d, pa, len, vring_index); - vring->ctx[i].mapped_as_page = 1; + /* no need to check return code - + * if it succeeded for 1-st descriptor, + * it will succeed here too + */ + wil_tx_desc_offload_cksum_set(wil, d, skb); *_d = *d; } /* for the last seg only */ @@ -808,7 +964,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* unmap what we have mapped */ nr_frags = f + 1; /* frags mapped + one for skb head */ for (f = 0; f < nr_frags; f++) { - u16 dmalen; struct wil_ctx *ctx; i = (swhead + f) % vring->size; @@ -816,12 +971,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, _d = &(vring->va[i].tx); *d = *_d; _d->dma.status = TX_DMA_STATUS_DU; - pa = wil_desc_addr(&d->dma.addr); - dmalen = le16_to_cpu(d->dma.length); - if (ctx->mapped_as_page) - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); - else - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + wil_txdesc_unmap(dev, d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); @@ -836,12 +986,17 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); + struct ethhdr *eth = (void *)skb->data; struct vring *vring; + static bool pr_once_fw; int rc; wil_dbg_txrx(wil, "%s()\n", __func__); if (!test_bit(wil_status_fwready, &wil->status)) { - wil_err(wil, "FW not ready\n"); + if (!pr_once_fw) { + wil_err(wil, "FW not ready\n"); + pr_once_fw = true; + } goto drop; } if (!test_bit(wil_status_fwconnected, &wil->status)) { @@ -852,16 +1007,25 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) wil_err(wil, "Xmit in monitor mode not supported\n"); goto drop; } + pr_once_fw = false; /* find vring */ - vring = wil_find_tx_vring(wil, skb); + if (is_unicast_ether_addr(eth->h_dest)) { + vring = wil_find_tx_vring(wil, skb); + } else { + vring = wil_tx_bcast(wil, skb); + } if (!vring) { - wil_err(wil, "No Tx VRING available\n"); + wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } /* set up vring entry */ rc = wil_tx_vring(wil, vring, skb); + /* do we still have enough room in the vring? */ + if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) + netif_tx_stop_all_queues(wil_to_ndev(wil)); + switch (rc) { case 0: /* statistics will be updated on the tx_complete */ @@ -891,66 +1055,84 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct net_device *ndev = wil_to_ndev(wil); struct device *dev = wil_to_dev(wil); struct vring *vring = &wil->vring_tx[ringid]; + struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; int done = 0; + int cid = wil->vring2cid_tid[ringid][0]; + struct wil_net_stats *stats = &wil->sta[cid].stats; + volatile struct vring_tx_desc *_d; if (!vring->va) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); return 0; } + if (!txdata->enabled) { + wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid); + return 0; + } + wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); while (!wil_vring_is_empty(vring)) { - volatile struct vring_tx_desc *_d = - &vring->va[vring->swtail].tx; - struct vring_tx_desc dd, *d = ⅆ - dma_addr_t pa; - u16 dmalen; + int new_swtail; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; - struct sk_buff *skb = ctx->skb; - - *d = *_d; + /** + * For the fragmented skb, HW will set DU bit only for the + * last fragment. look for it + */ + int lf = (vring->swtail + ctx->nr_frags) % vring->size; + /* TODO: check we are not past head */ - if (!(d->dma.status & TX_DMA_STATUS_DU)) + _d = &vring->va[lf].tx; + if (!(_d->dma.status & TX_DMA_STATUS_DU)) break; - dmalen = le16_to_cpu(d->dma.length); - trace_wil6210_tx_done(ringid, vring->swtail, dmalen, - d->dma.error); - wil_dbg_txrx(wil, - "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", - vring->swtail, dmalen, d->dma.status, - d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, - (const void *)d, sizeof(*d), false); - - pa = wil_desc_addr(&d->dma.addr); - if (ctx->mapped_as_page) - dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); - else - dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); - - if (skb) { - if (d->dma.error == 0) { - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += skb->len; - } else { - ndev->stats.tx_errors++; - } + new_swtail = (lf + 1) % vring->size; + while (vring->swtail != new_swtail) { + struct vring_tx_desc dd, *d = ⅆ + u16 dmalen; + struct wil_ctx *ctx = &vring->ctx[vring->swtail]; + struct sk_buff *skb = ctx->skb; + _d = &vring->va[vring->swtail].tx; + + *d = *_d; + + dmalen = le16_to_cpu(d->dma.length); + trace_wil6210_tx_done(ringid, vring->swtail, dmalen, + d->dma.error); + wil_dbg_txrx(wil, + "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", + vring->swtail, dmalen, d->dma.status, + d->dma.error); + wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); + + wil_txdesc_unmap(dev, d, ctx); + + if (skb) { + if (d->dma.error == 0) { + ndev->stats.tx_packets++; + stats->tx_packets++; + ndev->stats.tx_bytes += skb->len; + stats->tx_bytes += skb->len; + } else { + ndev->stats.tx_errors++; + stats->tx_errors++; + } - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb); + } + memset(ctx, 0, sizeof(*ctx)); + /* There is no need to touch HW descriptor: + * - ststus bit TX_DMA_STATUS_DU is set by design, + * so hardware will not try to process this desc., + * - rest of descriptor will be initialized on Tx. + */ + vring->swtail = wil_vring_next_tail(vring); + done++; } - memset(ctx, 0, sizeof(*ctx)); - /* - * There is no need to touch HW descriptor: - * - ststus bit TX_DMA_STATUS_DU is set by design, - * so hardware will not try to process this desc., - * - rest of descriptor will be initialized on Tx. - */ - vring->swtail = wil_vring_next_tail(vring); - done++; } - if (wil_vring_avail_tx(vring) > vring->size/4) + if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) netif_tx_wake_all_queues(wil_to_ndev(wil)); return done; diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index b3828279204..bc5706a4f00 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) return (void *)skb->cb; } +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, + int size, u16 ssn); +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r); + #endif /* WIL6210_TXRX_H */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1f91eaf95bb..e25edc52398 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -35,11 +35,14 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) #define WIL6210_RX_RING_SIZE (128) -#define WIL6210_TX_RING_SIZE (128) +#define WIL6210_TX_RING_SIZE (512) #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ #define WIL6210_MAX_CID (8) /* HW limit */ #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ #define WIL6210_ITR_TRSH (10000) /* arbitrary - about 15 IRQs/msec */ +#define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ +#define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000) +#define WIL6210_SCAN_TO msecs_to_jiffies(10000) /* Hardware definitions begin */ @@ -74,23 +77,21 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ -#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) -#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ - #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) -#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) -#define RGF_USER_MAC_CPU_0 (0x8801fc) +#define RGF_USER_HW_MACHINE_STATE (0x8801dc) + #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) +#define RGF_USER_MAC_CPU_0 (0x8801fc) +#define RGF_USER_USER_SCRATCH_PAD (0x8802bc) +#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ +#define RGF_USER_CLKS_CTL_0 (0x880abc) + #define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */ #define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) #define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) #define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) #define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10) - -#define RGF_DMA_PSEUDO_CAUSE (0x881c68) -#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) -#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) - #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) - #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) - #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) +#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) +#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ + #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) @@ -105,13 +106,22 @@ struct RGF_ICR { /* Interrupt moderation control */ #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) #define RGF_DMA_ITR_CNT_DATA (0x881c60) -#define RGF_DMA_ITR_CNT_CRL (0x881C64) +#define RGF_DMA_ITR_CNT_CRL (0x881c64) #define BIT_DMA_ITR_CNT_CRL_EN BIT(0) #define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1) #define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2) #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +#define RGF_DMA_PSEUDO_CAUSE (0x881c68) +#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) +#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) + #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) + #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) + #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) + +#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) + /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ @@ -125,6 +135,31 @@ struct RGF_ICR { /* Hardware definitions end */ +/** + * mk_cidxtid - construct @cidxtid field + * @cid: CID value + * @tid: TID value + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline u8 mk_cidxtid(u8 cid, u8 tid) +{ + return ((tid & 0xf) << 4) | (cid & 0xf); +} + +/** + * parse_cidxtid - parse @cidxtid field + * @cid: store CID value here + * @tid: store TID value here + * + * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + */ +static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) +{ + *cid = cidxtid & 0xf; + *tid = (cidxtid >> 4) & 0xf; +} + struct wil6210_mbox_ring { u32 base; u16 entry_size; /* max. size of mbox entry, incl. all headers */ @@ -184,12 +219,19 @@ struct pending_wmi_event { } __packed event; }; +enum { /* for wil_ctx.mapped_as */ + wil_mapped_as_none = 0, + wil_mapped_as_single = 1, + wil_mapped_as_page = 2, +}; + /** * struct wil_ctx - software context for Vring descriptor */ struct wil_ctx { struct sk_buff *skb; - u8 mapped_as_page:1; + u8 nr_frags; + u8 mapped_as; }; union vring_desc; @@ -204,6 +246,14 @@ struct vring { struct wil_ctx *ctx; /* ctx[size] - software context */ }; +/** + * Additional data for Tx Vring + */ +struct vring_tx_data { + int enabled; + +}; + enum { /* for wil6210_priv.status */ wil_status_fwready = 0, wil_status_fwconnecting, @@ -211,10 +261,52 @@ enum { /* for wil6210_priv.status */ wil_status_dontscan, wil_status_reset_done, wil_status_irqen, /* FIXME: interrupts enabled - for debug */ + wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ }; struct pci_dev; +/** + * struct tid_ampdu_rx - TID aggregation information (Rx). + * + * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @reorder_time: jiffies when skb was added + * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) + * @reorder_timer: releases expired frames from the reorder buffer. + * @last_rx: jiffies of last rx activity + * @head_seq_num: head sequence number in reordering buffer. + * @stored_mpdu_num: number of MPDUs in reordering buffer + * @ssn: Starting Sequence Number expected to be aggregated. + * @buf_size: buffer size for incoming A-MPDUs + * @timeout: reset timer value (in TUs). + * @dialog_token: dialog token for aggregation session + * @rcu_head: RCU head used for freeing this struct + * @reorder_lock: serializes access to reorder buffer, see below. + * + * This structure's lifetime is managed by RCU, assignments to + * the array holding it must hold the aggregation mutex. + * + * The @reorder_lock is used to protect the members of this + * struct, except for @timeout, @buf_size and @dialog_token, + * which are constant across the lifetime of the struct (the + * dialog token being used only for debugging). + */ +struct wil_tid_ampdu_rx { + spinlock_t reorder_lock; /* see above */ + struct sk_buff **reorder_buf; + unsigned long *reorder_time; + struct timer_list session_timer; + struct timer_list reorder_timer; + unsigned long last_rx; + u16 head_seq_num; + u16 stored_mpdu_num; + u16 ssn; + u16 buf_size; + u16 timeout; + u8 dialog_token; + bool first_time; /* is it 1-st time this buffer used? */ +}; + struct wil6210_stats { u64 tsf; u32 snr; @@ -226,6 +318,43 @@ struct wil6210_stats { u16 peer_tx_sector; }; +enum wil_sta_status { + wil_sta_unused = 0, + wil_sta_conn_pending = 1, + wil_sta_connected = 2, +}; + +#define WIL_STA_TID_NUM (16) + +struct wil_net_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long tx_errors; + unsigned long rx_dropped; + u16 last_mcs_rx; +}; + +/** + * struct wil_sta_info - data for peer + * + * Peer identified by its CID (connection ID) + * NIC performs beam forming for each peer; + * if no beam forming done, frame exchange is not + * possible. + */ +struct wil_sta_info { + u8 addr[ETH_ALEN]; + enum wil_sta_status status; + struct wil_net_stats stats; + bool data_port_open; /* can send any data, not only EAPOL */ + /* Rx BACK */ + struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; + unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; + unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -233,7 +362,10 @@ struct wil6210_priv { void __iomem *csr; ulong status; u32 fw_version; + u32 hw_version; u8 n_mids; /* number of additional MIDs as reported by FW */ + int recovery_count; /* num of FW recovery attempts in a short time */ + unsigned long last_fw_recovery; /* jiffies of last fw recovery */ /* profile */ u32 monitor_flags; u32 secure_pcp; /* create secure PCP? */ @@ -253,7 +385,9 @@ struct wil6210_priv { struct workqueue_struct *wmi_wq_conn; /* for connect worker */ struct work_struct connect_worker; struct work_struct disconnect_worker; + struct work_struct fw_error_worker; /* for FW error recovery */ struct timer_list connect_timer; + struct timer_list scan_timer; /* detect scan timeout */ int pending_connect_cid; struct list_head pending_wmi_ev; /* @@ -267,7 +401,9 @@ struct wil6210_priv { /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; - u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; + struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; + u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ + struct wil_sta_info sta[WIL6210_MAX_CID]; /* scan */ struct cfg80211_scan_request *scan_request; @@ -329,11 +465,13 @@ void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); +void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_link_on(struct wil6210_priv *wil); void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); @@ -357,8 +495,11 @@ int wmi_echo(struct wil6210_priv *wil); int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); +int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); +void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil6210_disable_irq(struct wil6210_priv *wil); @@ -373,7 +514,7 @@ void wil_wdev_free(struct wil6210_priv *wil); int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); int wmi_pcp_stop(struct wil6210_priv *wil); -void wil6210_disconnect(struct wil6210_priv *wil, void *bssid); +void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid); int wil_rx_init(struct wil6210_priv *wil); void wil_rx_fini(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 063963ee422..6cc0e182cc7 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -192,7 +192,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) might_sleep(); if (!test_bit(wil_status_fwready, &wil->status)) { - wil_err(wil, "FW not ready\n"); + wil_err(wil, "WMI: cannot send command while FW not ready\n"); return -EAGAIN; } @@ -276,8 +276,8 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) wil->fw_version = le32_to_cpu(evt->sw_version); wil->n_mids = evt->numof_additional_mids; - wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, - evt->mac, wil->n_mids); + wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, + evt->mac, wil->n_mids); if (!is_valid_ether_addr(ndev->dev_addr)) { memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); @@ -290,7 +290,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, int len) { - wil_dbg_wmi(wil, "WMI: FW ready\n"); + wil_dbg_wmi(wil, "WMI: got FW ready event\n"); set_bit(wil_status_fwready, &wil->status); /* reuse wmi_ready for the firmware ready indication */ @@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) u32 freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ); struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); - /* TODO convert LE to CPU */ - s32 signal = 0; /* TODO */ + s32 signal = data->info.sqi; __le16 fc = rx_mgmt_frame->frame_control; u32 d_len = le32_to_cpu(data->info.len); u16 d_status = le16_to_cpu(data->info.status); - wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", - data->info.channel, data->info.mcs, data->info.snr); + wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", + data->info.channel, data->info.mcs, data->info.snr, + data->info.sqi); wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, le16_to_cpu(fc)); wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", @@ -348,9 +348,10 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, { if (wil->scan_request) { struct wmi_scan_complete_event *data = d; - bool aborted = (data->status != 0); + bool aborted = (data->status != WMI_SCAN_SUCCESS); wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); + del_timer_sync(&wil->scan_timer); cfg80211_scan_done(wil->scan_request, aborted); wil->scan_request = NULL; } else { @@ -384,6 +385,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) evt->assoc_req_len, evt->assoc_resp_len); return; } + if (evt->cid >= WIL6210_MAX_CID) { + wil_err(wil, "Connect CID invalid : %d\n", evt->cid); + return; + } + ch = evt->channel + 1; wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", evt->bssid, ch, evt->cid); @@ -439,7 +445,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) /* FIXME FW can transmit only ucast frames to peer */ /* FIXME real ring_id instead of hard coded 0 */ - memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); + memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN); + wil->sta[evt->cid].status = wil_sta_conn_pending; wil->pending_connect_cid = evt->cid; queue_work(wil->wmi_wq_conn, &wil->connect_worker); @@ -456,7 +463,9 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, wil->sinfo_gen++; + mutex_lock(&wil->mutex); wil6210_disconnect(wil, evt->bssid); + mutex_unlock(&wil->mutex); } static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) @@ -476,11 +485,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" - "BF status 0x%08x SNR 0x%08x\n" + "BF status 0x%08x SNR 0x%08x SQI %d%%\n" "Tx Tpt %d goodput %d Rx goodput %d\n" "Sectors(rx:tx) my %d:%d peer %d:%d\n", wil->stats.bf_mcs, wil->stats.tsf, evt->status, - wil->stats.snr, le32_to_cpu(evt->tx_tpt), + wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt), le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), wil->stats.my_rx_sector, wil->stats.my_tx_sector, wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); @@ -499,10 +508,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, int sz = eapol_len + ETH_HLEN; struct sk_buff *skb; struct ethhdr *eth; + int cid; + struct wil_net_stats *stats = NULL; wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, evt->src_mac); + cid = wil_find_cid(wil, evt->src_mac); + if (cid >= 0) + stats = &wil->sta[cid].stats; + if (eapol_len > 196) { /* TODO: revisit size limit */ wil_err(wil, "EAPOL too large\n"); return; @@ -513,6 +528,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, wil_err(wil, "Failed to allocate skb\n"); return; } + eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); memcpy(eth->h_source, evt->src_mac, ETH_ALEN); @@ -521,9 +537,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, skb->protocol = eth_type_trans(skb, ndev); if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { ndev->stats.rx_packets++; - ndev->stats.rx_bytes += skb->len; + ndev->stats.rx_bytes += sz; + if (stats) { + stats->rx_packets++; + stats->rx_bytes += sz; + } } else { ndev->stats.rx_dropped++; + if (stats) + stats->rx_dropped++; } } @@ -531,9 +553,16 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { struct net_device *ndev = wil_to_ndev(wil); struct wmi_data_port_open_event *evt = d; + u8 cid = evt->cid; + + wil_dbg_wmi(wil, "Link UP for CID %d\n", cid); - wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid); + if (cid >= ARRAY_SIZE(wil->sta)) { + wil_err(wil, "Link UP for invalid CID %d\n", cid); + return; + } + wil->sta[cid].data_port_open = true; netif_carrier_on(ndev); } @@ -541,10 +570,17 @@ static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) { struct net_device *ndev = wil_to_ndev(wil); struct wmi_wbe_link_down_event *evt = d; + u8 cid = evt->cid; wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n", - evt->cid, le32_to_cpu(evt->reason)); + cid, le32_to_cpu(evt->reason)); + if (cid >= ARRAY_SIZE(wil->sta)) { + wil_err(wil, "Link DOWN for invalid CID %d\n", cid); + return; + } + + wil->sta[cid].data_port_open = false; netif_carrier_off(ndev); } @@ -552,10 +588,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_vring_ba_status_event *evt = d; + struct wil_sta_info *sta; + uint i, cid; + + /* TODO: use Rx BA status, not Tx one */ wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", - evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, - __le16_to_cpu(evt->ba_timeout)); + evt->ringid, + evt->status == WMI_BA_AGREED ? "OK" : "N/A", + evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); + + if (evt->ringid >= WIL6210_MAX_TX_RINGS) { + wil_err(wil, "invalid ring id %d\n", evt->ringid); + return; + } + + cid = wil->vring2cid_tid[evt->ringid][0]; + if (cid >= WIL6210_MAX_CID) { + wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); + return; + } + + sta = &wil->sta[cid]; + if (sta->status == wil_sta_unused) { + wil_err(wil, "CID %d unused\n", cid); + return; + } + + wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) + sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, + evt->agg_wsize, 0); + } } static const struct { @@ -591,21 +659,27 @@ void wmi_recv_cmd(struct wil6210_priv *wil) u8 *cmd; void __iomem *src; ulong flags; + unsigned n; if (!test_bit(wil_status_reset_done, &wil->status)) { wil_err(wil, "Reset not completed\n"); return; } - for (;;) { + for (n = 0;; n++) { u16 len; r->head = ioread32(wil->csr + HOST_MBOX + offsetof(struct wil6210_mbox_ctl, rx.head)); - if (r->tail == r->head) + if (r->tail == r->head) { + if (n == 0) + wil_dbg_wmi(wil, "No events?\n"); return; + } - /* read cmd from tail */ + wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n", + r->head, r->tail); + /* read cmd descriptor from tail */ wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail), sizeof(struct wil6210_mbox_ring_desc)); if (d_tail.sync == 0) { @@ -613,13 +687,18 @@ void wmi_recv_cmd(struct wil6210_priv *wil) return; } + /* read cmd header from descriptor */ if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { wil_err(wil, "Mbox evt at 0x%08x?\n", le32_to_cpu(d_tail.addr)); return; } - len = le16_to_cpu(hdr.len); + wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", + le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), + hdr.flags); + + /* read cmd buffer from descriptor */ src = wmi_buffer(wil, d_tail.addr) + sizeof(struct wil6210_mbox_hdr); evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event, @@ -635,9 +714,6 @@ void wmi_recv_cmd(struct wil6210_priv *wil) iowrite32(0, wil->csr + HOSTADDR(r->tail) + offsetof(struct wil6210_mbox_ring_desc, sync)); /* indicate */ - wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", - le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), - hdr.flags); if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi; @@ -667,6 +743,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) wil_dbg_wmi(wil, "queue_work -> %d\n", q); } } + if (n > 1) + wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n); } int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, @@ -735,6 +813,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) .network_type = wmi_nettype, .disable_sec_offload = 1, .channel = chan - 1, + .pcp_max_assoc_sta = WIL6210_MAX_CID, }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -893,6 +972,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) return rc; } +/** + * wmi_rxon - turn radio on/off + * @on: turn on if true, off otherwise + * + * Only switch radio. Channel should be set separately. + * No timeout for rxon - radio turned on forever unless some other call + * turns it off + */ +int wmi_rxon(struct wil6210_priv *wil, bool on) +{ + int rc; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_listen_started_event evt; + } __packed reply; + + wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off"); + + if (on) { + rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, + WMI_LISTEN_STARTED_EVENTID, + &reply, sizeof(reply), 100); + if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) + rc = -EINVAL; + } else { + rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, + WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); + } + + return rc; +} + int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) { struct wireless_dev *wdev = wil->wdev; @@ -906,6 +1017,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) }, .mid = 0, /* TODO - what is it? */ .decap_trans_type = WMI_DECAP_TYPE_802_3, + .reorder_type = WMI_RX_SW_REORDER, }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -973,6 +1085,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) return 0; } +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) +{ + struct wmi_disconnect_sta_cmd cmd = { + .disconnect_reason = cpu_to_le16(reason), + }; + memcpy(cmd.dst_mac, mac, ETH_ALEN); + + wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); + + return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); +} + void wmi_event_flush(struct wil6210_priv *wil) { struct pending_wmi_event *evt, *t; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 50b8528394f..17334c85286 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -28,7 +28,7 @@ #define __WILOCITY_WMI_H__ /* General */ - +#define WILOCITY_MAX_ASSOC_STA (8) #define WMI_MAC_LEN (6) #define WMI_PROX_RANGE_NUM (3) @@ -219,15 +219,6 @@ struct wmi_disconnect_sta_cmd { __le16 disconnect_reason; } __packed; -/* - * WMI_RECONNECT_CMDID - */ -struct wmi_reconnect_cmd { - u8 channel; /* hint */ - u8 reserved; - u8 bssid[WMI_MAC_LEN]; /* mandatory if set */ -} __packed; - /* * WMI_SET_PMK_CMDID @@ -296,11 +287,13 @@ enum wmi_scan_type { WMI_LONG_SCAN = 0, WMI_SHORT_SCAN = 1, WMI_PBC_SCAN = 2, + WMI_ACTIVE_SCAN = 3, + WMI_DIRECT_SCAN = 4, }; struct wmi_start_scan_cmd { - u8 reserved[8]; - + u8 direct_scan_mac_addr[6]; + u8 reserved[2]; __le32 home_dwell_time; /* Max duration in the home channel(ms) */ __le32 force_scan_interval; /* Time interval between scans (ms)*/ u8 scan_type; /* wmi_scan_type */ @@ -332,6 +325,7 @@ struct wmi_probed_ssid_cmd { u8 ssid[WMI_MAX_SSID_LEN]; } __packed; + /* * WMI_SET_APPIE_CMDID * Add Application specified IE to a management frame @@ -427,7 +421,7 @@ struct wmi_bcon_ctrl_cmd { __le16 frag_num; __le64 ss_mask; u8 network_type; - u8 reserved; + u8 pcp_max_assoc_sta; u8 disable_sec_offload; u8 disable_sec; } __packed; @@ -450,7 +444,7 @@ enum wmi_port_role { struct wmi_port_allocate_cmd { u8 mac[WMI_MAC_LEN]; u8 port_role; - u8 midid; + u8 mid; } __packed; /* @@ -467,6 +461,7 @@ struct wmi_delete_port_cmd { enum wmi_discovery_mode { WMI_DISCOVERY_MODE_NON_OFFLOAD = 0, WMI_DISCOVERY_MODE_OFFLOAD = 1, + WMI_DISCOVERY_MODE_PEER2PEER = 2, }; struct wmi_p2p_cfg_cmd { @@ -493,7 +488,8 @@ struct wmi_power_mgmt_cfg_cmd { */ struct wmi_pcp_start_cmd { __le16 bcon_interval; - u8 reserved0[10]; + u8 pcp_max_assoc_sta; + u8 reserved0[9]; u8 network_type; u8 channel; u8 disable_sec_offload; @@ -857,6 +853,7 @@ enum wmi_event_id { WMI_RF_MGMT_STATUS_EVENTID = 0x1853, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, + WMI_TX_MGMT_PACKET_EVENTID = 0x1841, /* Performance monitoring events */ WMI_DATA_PORT_OPEN_EVENTID = 0x1860, @@ -1040,16 +1037,23 @@ enum wmi_disconnect_reason { struct wmi_disconnect_event { __le16 protocol_reason_status; /* reason code, see 802.11 spec. */ u8 bssid[WMI_MAC_LEN]; /* set if known */ - u8 disconnect_reason; /* see wmi_disconnect_reason_e */ - u8 assoc_resp_len; - u8 assoc_info[0]; + u8 disconnect_reason; /* see wmi_disconnect_reason */ + u8 assoc_resp_len; /* not in use */ + u8 assoc_info[0]; /* not in use */ } __packed; /* * WMI_SCAN_COMPLETE_EVENTID */ +enum scan_status { + WMI_SCAN_SUCCESS = 0, + WMI_SCAN_FAILED = 1, + WMI_SCAN_ABORTED = 2, + WMI_SCAN_REJECTED = 3, +}; + struct wmi_scan_complete_event { - __le32 status; + __le32 status; /* scan_status */ } __packed; /* @@ -1256,6 +1260,14 @@ struct wmi_rx_mgmt_info { u8 channel; /* From Radio MNGR */ } __packed; + +/* + * WMI_TX_MGMT_PACKET_EVENTID + */ +struct wmi_tx_mgmt_packet_event { + u8 payload[0]; +} __packed; + struct wmi_rx_mgmt_packet_event { struct wmi_rx_mgmt_info info; u8 payload[0]; |
