diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k')
20 files changed, 1981 insertions, 1338 deletions
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index a1f099628850..17d221abd58c 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 8d81ce1cec21..111ab701465c 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 a79499c82350..d185dc0cd12b 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -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; /* @@ -1074,64 +1083,128 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, 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 8eb7f99ed992..7a5a36fc59c1 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -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 { @@ -159,6 +160,8 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, 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); @@ -210,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=======================*/ /* @@ -236,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 ebc5fc2ede75..82017f56e661 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -58,36 +58,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) complete(&ar->target_suspend); } -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; -} - static int ath10k_init_configure_target(struct ath10k *ar) { u32 param_host; @@ -249,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) @@ -389,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); } @@ -401,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; } @@ -430,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; @@ -513,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; } @@ -531,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; } @@ -549,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; @@ -572,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; } @@ -660,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: @@ -670,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 */ @@ -681,70 +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->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->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; @@ -785,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); @@ -797,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); @@ -813,31 +775,36 @@ 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; 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); @@ -845,12 +812,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: @@ -885,10 +854,14 @@ void ath10k_core_stop(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); /* try to suspend target */ - ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); + 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); @@ -980,22 +953,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); @@ -1010,18 +976,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. */ @@ -1033,6 +1024,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 0e71979d837c..68ceef61933d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -119,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 { @@ -130,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; @@ -260,6 +267,8 @@ struct ath10k_vif { u8 fixed_rate; u8 fixed_nss; u8 force_sgi; + bool use_cts_prot; + int num_legacy_stations; }; struct ath10k_vif_iter { @@ -326,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 { @@ -419,13 +429,24 @@ struct ath10k { 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; @@ -456,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. diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 6debd281350a..1b7ff4ba122c 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/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 7f1bccd3597f..e493db4b4a41 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -157,6 +157,9 @@ 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); } @@ -185,6 +188,9 @@ 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) @@ -234,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); @@ -824,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 69697af59ce0..19c12cc8d663 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 654867fc1ae7..9a263462c793 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -21,6 +21,7 @@ #include <linux/bug.h> #include <linux/interrupt.h> #include <linux/dmapool.h> +#include <net/mac80211.h> #include "htc.h" #include "rx_desc.h" @@ -1172,23 +1173,6 @@ 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; - - u32 tsf; - 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; @@ -1289,6 +1273,9 @@ struct ath10k_htt { 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 @@ -1341,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); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index cdcbe2de95f9..6c102b1312ff 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -225,10 +225,26 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg) ath10k_htt_rx_msdu_buff_replenish(htt); } -void ath10k_htt_rx_detach(struct ath10k_htt *htt) +static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt) { - int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld; + 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_free(struct ath10k_htt *htt) +{ del_timer_sync(&htt->rx_ring.refill_retry_timer); tasklet_kill(&htt->rx_replenish_task); tasklet_kill(&htt->txrx_compl_task); @@ -236,18 +252,7 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt) skb_queue_purge(&htt->tx_compl_q); skb_queue_purge(&htt->rx_compl_q); - 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); - - 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 * @@ -277,6 +282,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) 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; @@ -297,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, @@ -305,12 +312,13 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, int msdu_len, msdu_chaining = 0; struct sk_buff *msdu; struct htt_rx_desc *rx_desc; + bool corrupted = false; 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); @@ -398,7 +406,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0), RX_MSDU_START_INFO0_MSDU_LENGTH); msdu_chained = rx_desc->frag_info.ring2_more_count; - msdu_chaining = msdu_chained; if (msdu_len_invalid) msdu_len = 0; @@ -426,11 +433,15 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->next = next; msdu = next; + msdu_chaining = 1; } last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & RX_MSDU_END_INFO0_LAST_MSDU; + if (msdu_chaining && !last_msdu) + corrupted = true; + if (last_msdu) { msdu->next = NULL; break; @@ -442,6 +453,23 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, } *tail_msdu = msdu; + if (*head_msdu == NULL) + msdu_chaining = -1; + + /* + * Apparently FW sometimes reports weird chained MSDU sequences with + * more than one rx descriptor. This seems like a bug but needs more + * analyzing. For the time being fix it by dropping such sequences to + * avoid blowing up the host system. + */ + if (corrupted) { + ath10k_warn("failed to pop chained msdus, dropping\n"); + ath10k_htt_rx_free_msdu_chain(*head_msdu); + *head_msdu = NULL; + *tail_msdu = NULL; + msdu_chaining = -EINVAL; + } + /* * Don't refill the ring yet. * @@ -464,7 +492,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; @@ -490,7 +518,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; @@ -636,6 +664,203 @@ 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 */ @@ -643,11 +868,12 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) } 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; @@ -728,24 +954,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; @@ -808,66 +1038,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; -} - -static bool ath10k_htt_rx_is_mgmt(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_MGMT_TYPE) - return true; - - return false; + ath10k_process_rx(htt->ar, rx_status, skb); } static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) @@ -952,21 +1125,73 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head) 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; lockdep_assert_held(&htt->rx_ring.lock); - memset(&info, 0, sizeof(info)); - fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); fw_desc = (u8 *)&rx->fw_desc; @@ -974,106 +1199,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_dbg(ATH10K_DBG_HTT, - "htt rx dropping due to decrypt-err\n"); - 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 || - ath10k_htt_rx_is_mgmt(msdu_head)) { - ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); + 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 && - status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && - !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_dbg(ATH10K_DBG_HTT, - "htt rx CAC running\n"); - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - if (msdu_chaining && - (ath10k_unchain_msdu(msdu_head) < 0)) { - 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); - - if (info.fcs_err) - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx has FCS err\n"); - - if (info.mic_err) - ath10k_dbg(ATH10K_DBG_HTT, - "htt rx has MIC err\n"); - - 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); - info.tsf = __le32_to_cpu(rx->ppdu.tsf); + 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); } } @@ -1084,11 +1293,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; @@ -1102,24 +1312,21 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, msdu_tail = NULL; spin_lock_bh(&htt->rx_ring.lock); - msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, - &msdu_head, &msdu_tail); + ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, + &msdu_head, &msdu_tail); spin_unlock_bh(&htt->rx_ring.lock); ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); - if (!msdu_head) { - ath10k_warn("htt rx frag no data\n"); - return; - } - - 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); @@ -1136,57 +1343,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 rx frag mpdu: ", - info.skb->data, info.skb->len); - ath10k_process_rx(htt->ar, &info); + msdu_head->data, msdu_head->len); + ath10k_process_rx(htt->ar, rx_status, msdu_head); end: if (fw_desc_len > 0) { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 7a3e2e40dd5c..7064354d1f4f 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); @@ -120,7 +120,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt) 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; @@ -141,9 +141,9 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) 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); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 35fc44e281f5..007e855f4ba9 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 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 511a2f81e7af..a21080028c54 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,14 +327,14 @@ 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 %pM on vdev %i: %i\n", + 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 %pM on vdev %i: %i\n", + ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n", addr, vdev_id, ret); return ret; } @@ -351,7 +355,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) 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", + ath10k_warn("failed to set kickout threshold on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -360,7 +364,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) 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", + ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -369,7 +373,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) 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", + ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -378,7 +382,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) 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", + ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -488,92 +492,20 @@ 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 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)); + "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_start(ar, &arg); - if (ret) { - ath10k_warn("WMI vdev %i start failed: ret %d\n", - arg.vdev_id, ret); - return ret; - } - - ret = ath10k_vdev_setup_sync(ar); - if (ret) { - ath10k_warn("vdev %i setup failed %d\n", - arg.vdev_id, ret); - return ret; - } - - return ret; + return ar->promisc || ar->monitor || + test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); } -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("WMI vdev %i stop failed: ret %d\n", - arvif->vdev_id, ret); - return ret; - } - - ret = ath10k_vdev_setup_sync(ar); - if (ret) { - ath10k_warn("vdev %i setup sync failed %d\n", - arvif->vdev_id, ret); - return ret; - } - - return ret; -} - -static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) +static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = &ar->chandef; struct ieee80211_channel *channel = chandef->chan; @@ -582,11 +514,6 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) 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 = chandef->center_freq1; @@ -604,88 +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 %i start failed: ret %d\n", + 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 %i setup failed %d\n", + 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 %i up failed: %d\n", + 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 %i stop failed: %d\n", + 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 %i down failed: %d\n", + 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 %i stop failed: %d\n", + 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, vdev %i: %d\n", + 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; } @@ -696,7 +610,7 @@ static int ath10k_monitor_create(struct ath10k *ar) WMI_VDEV_TYPE_MONITOR, 0, ar->mac_addr); if (ret) { - ath10k_warn("WMI vdev %i monitor create failed: ret %d\n", + ath10k_warn("failed to request monitor vdev %i creation: %d\n", ar->monitor_vdev_id, ret); goto vdev_fail; } @@ -704,7 +618,6 @@ static int ath10k_monitor_create(struct ath10k *ar) ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n", ar->monitor_vdev_id); - ar->monitor_present = true; return 0; vdev_fail: @@ -715,48 +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 %i monitor delete failed: %d\n", + 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_start(ar, ar->monitor_vdev_id); + 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; + } + + 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; } @@ -774,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) +static void ath10k_recalc_radar_detection(struct ath10k *ar) { - 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) -{ - 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); @@ -835,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) { @@ -880,7 +931,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("Failed to bring up vdev %d: %i\n", + ath10k_warn("failed to bring up vdev %d: %i\n", arvif->vdev_id, ret); ath10k_vdev_stop(arvif); return; @@ -904,7 +955,7 @@ 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->bssid)) @@ -913,7 +964,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, arvif->bssid); if (ret) { - ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n", + ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", arvif->bssid, arvif->vdev_id, ret); return; } @@ -925,7 +976,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, 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; } @@ -934,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); } @@ -961,7 +1012,7 @@ 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: %i\n", + ath10k_warn("failed to set inactivity time for vdev %d: %i\n", arvif->vdev_id, ret); return ret; } @@ -974,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; } @@ -1429,7 +1480,7 @@ 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, vdev %i\n", + ath10k_warn("failed to find station entry for bss %pM vdev %i\n", bss_conf->bssid, arvif->vdev_id); rcu_read_unlock(); return; @@ -1442,7 +1493,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, bss_conf, &peer_arg); if (ret) { - ath10k_warn("Peer assoc prepare failed for %pM vdev %i\n: %d", + ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); rcu_read_unlock(); return; @@ -1452,7 +1503,7 @@ 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 vdev %i\n: %d", + ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); return; } @@ -1473,7 +1524,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("VDEV: %d up failed: ret %d\n", + ath10k_warn("failed to set vdev %d up: %d\n", arvif->vdev_id, ret); return; } @@ -1524,7 +1575,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, } 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; @@ -1533,34 +1584,46 @@ 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 vdev %i: %i\n", + 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 vdev %i: %d\n", + 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\n", 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 for vdev %i: %d\n", + 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("could not set qos params for STA %pM for vdev %i: %d\n", + ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n", sta->addr, arvif->vdev_id, ret); return ret; } @@ -1575,9 +1638,19 @@ 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 for vdev %i: %d\n", + ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } @@ -1685,19 +1758,44 @@ 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, @@ -1705,9 +1803,10 @@ static void ath10k_regd_update(struct ath10k *ar) 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, @@ -1725,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); } @@ -1759,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; } @@ -1792,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); @@ -1803,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) @@ -1879,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; } @@ -1903,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); } } @@ -1964,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); } @@ -1984,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); } @@ -2018,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); } } @@ -2043,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); @@ -2079,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); @@ -2099,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; @@ -2187,72 +2297,171 @@ 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", - ret); + 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 @@ -2266,15 +2475,27 @@ static int ath10k_start(struct ieee80211_hw *hw) ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->arp_ac_override, 0); if (ret) { - ath10k_warn("could not set arp ac override parameter: %d\n", + ath10k_warn("failed to set arp ac override parameter: %d\n", ret); - goto exit; + goto err_core_stop; } + ar->num_started_vdevs = 0; ath10k_regd_update(ar); - ret = 0; -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; } @@ -2283,19 +2504,15 @@ 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); } @@ -2309,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; } } @@ -2343,7 +2560,6 @@ static const char *chandef_get_width(enum nl80211_chan_width width) static void ath10k_config_chan(struct ath10k *ar) { struct ath10k_vif *arvif; - bool monitor_was_enabled; int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2357,10 +2573,8 @@ static void ath10k_config_chan(struct ath10k *ar) /* First stop monitor interface. Some FW versions crash if there's a * lone monitor interface. */ - monitor_was_enabled = ar->monitor_enabled; - - if (ar->monitor_enabled) - ath10k_monitor_stop(ar); + if (ar->monitor_started) + ath10k_monitor_vdev_stop(ar); list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_started) @@ -2371,7 +2585,7 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_vdev_stop(arvif); if (ret) { - ath10k_warn("could not stop vdev %d (%d)\n", + ath10k_warn("failed to stop vdev %d: %d\n", arvif->vdev_id, ret); continue; } @@ -2388,7 +2602,7 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_vdev_start(arvif); if (ret) { - ath10k_warn("could not start vdev %d (%d)\n", + ath10k_warn("failed to start vdev %d: %d\n", arvif->vdev_id, ret); continue; } @@ -2399,14 +2613,14 @@ static void ath10k_config_chan(struct ath10k *ar) ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { - ath10k_warn("could not bring vdev up %d (%d)\n", + ath10k_warn("failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); continue; } } - if (monitor_was_enabled) - ath10k_monitor_start(ar, ar->monitor_vdev_id); + 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) @@ -2420,15 +2634,17 @@ 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; @@ -2444,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); } @@ -2459,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); @@ -2497,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; @@ -2545,7 +2764,7 @@ 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 %i create failed: ret %d\n", + ath10k_warn("failed to create WMI vdev %i: %d\n", arvif->vdev_id, ret); goto err; } @@ -2557,7 +2776,7 @@ 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 vdev %i default keyid: %d\n", + ath10k_warn("failed to set vdev %i default key id: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2567,7 +2786,7 @@ 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 vdev %i TX encap: %d\n", + ath10k_warn("failed to set vdev %i TX encapsulation: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } @@ -2575,14 +2794,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, 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 vdev %i peer for AP: %d\n", + ath10k_warn("failed to create vdev %i peer for AP: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } ret = ath10k_mac_set_kickout(arvif); if (ret) { - ath10k_warn("Failed to set vdev %i kickout parameters: %d\n", + ath10k_warn("failed to set vdev %i kickout parameters: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2594,7 +2813,7 @@ 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 vdev %i RX wake policy: %d\n", + ath10k_warn("failed to set vdev %i RX wake policy: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2604,7 +2823,7 @@ 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 vdev %i TX wake thresh: %d\n", + ath10k_warn("failed to set vdev %i TX wake thresh: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2614,7 +2833,7 @@ 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 vdev %i PSPOLL count: %d\n", + ath10k_warn("failed to set vdev %i PSPOLL count: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -2622,21 +2841,18 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, 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; @@ -2668,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; } @@ -2679,7 +2898,7 @@ 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 vdev %i: %d\n", + ath10k_warn("failed to remove peer for AP vdev %i: %d\n", arvif->vdev_id, ret); kfree(arvif->u.ap.noa_data); @@ -2690,12 +2909,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id); if (ret) - ath10k_warn("WMI vdev %i delete failed: %d\n", + ath10k_warn("failed to delete WMI vdev %i: %d\n", arvif->vdev_id, ret); - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - ar->monitor_present = false; - ath10k_peer_cleanup(ar, arvif->vdev_id); mutex_unlock(&ar->conf_mutex); @@ -2728,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); @@ -2780,7 +2985,7 @@ 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: %i\n", + ath10k_warn("failed to set beacon interval for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2793,7 +2998,7 @@ 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: %i\n", + ath10k_warn("failed to set beacon mode for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2808,7 +3013,7 @@ 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: %i\n", + ath10k_warn("failed to set dtim period for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2820,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", @@ -2829,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 changing 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) { @@ -2868,20 +3078,13 @@ 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: %d\n", + ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n", arvif->vdev_id, ret); } @@ -2900,7 +3103,7 @@ 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: %i\n", + ath10k_warn("failed to set erp slot for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2919,7 +3122,7 @@ 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: %i\n", + ath10k_warn("failed to set preamble for vdev %d: %i\n", arvif->vdev_id, ret); } @@ -2990,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); @@ -3010,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); @@ -3089,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; @@ -3112,7 +3314,7 @@ 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("key installation failed for vdev %i peer %pM: %d\n", + ath10k_warn("failed to install key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); goto exit; } @@ -3127,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: @@ -3195,6 +3397,16 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) 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); } @@ -3236,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; @@ -3248,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)) { @@ -3260,7 +3472,7 @@ 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: %i\n", + ath10k_warn("failed to delete peer %pM for vdev %d: %i\n", sta->addr, arvif->vdev_id, ret); if (vif->type == NL80211_IFTYPE_STATION) @@ -3275,9 +3487,9 @@ 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 for vdev %i: %i\n", + 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 && @@ -3291,7 +3503,7 @@ 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 vdev %i ret %i\n", + ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); } exit: @@ -3339,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; } @@ -3352,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; @@ -3402,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); @@ -3461,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); @@ -3470,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; @@ -3511,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; } @@ -3534,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; } @@ -3544,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; @@ -3573,7 +3786,7 @@ 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 (skip %i ar-state %i): %i\n", + ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n", skip, ar->state, ret); skip: @@ -3608,7 +3821,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw, 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; } @@ -3617,7 +3830,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw, resume: ret = ath10k_wmi_pdev_resume_target(ar); if (ret) - ath10k_warn("could not resume target (%d)\n", ret); + ath10k_warn("failed to resume target: %d\n", ret); ret = 1; exit: @@ -3634,14 +3847,14 @@ static int ath10k_resume(struct ieee80211_hw *hw) ret = ath10k_hif_resume(ar); if (ret) { - ath10k_warn("could not resume hif (%d)\n", ret); + 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); + ath10k_warn("failed to resume target: %d\n", ret); ret = 1; goto exit; } @@ -3964,7 +4177,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, 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; @@ -3977,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; @@ -3990,7 +4203,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif, force_sgi); if (ret) { - ath10k_warn("Could not set sgi param %d: %d\n", + ath10k_warn("failed to set sgi param %d: %d\n", force_sgi, ret); ret = -EINVAL; goto exit; @@ -4026,7 +4239,7 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, } if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) { - ath10k_warn("Could not force SGI usage for default rate settings\n"); + ath10k_warn("failed to force SGI usage for default rate settings\n"); return -EINVAL; } @@ -4034,14 +4247,6 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, fixed_nss, force_sgi); } -static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_chan_def *chandef) -{ - /* there's no need to do anything here. vif->csa_active is enough */ - return; -} - static void ath10k_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -4072,8 +4277,8 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, bw = WMI_PEER_CHWIDTH_80MHZ; break; case IEEE80211_STA_RX_BW_160: - ath10k_warn("mac sta rc update for %pM: invalid bw %d\n", - sta->addr, sta->bandwidth); + ath10k_warn("Invalid bandwith %d in rc update for %pM\n", + sta->bandwidth, sta->addr); bw = WMI_PEER_CHWIDTH_20MHZ; break; } @@ -4099,8 +4304,8 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, smps = WMI_PEER_SMPS_DYNAMIC; break; case IEEE80211_SMPS_NUM_MODES: - ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n", - sta->addr, sta->smps_mode); + ath10k_warn("Invalid smps %d in sta rc update for %pM\n", + sta->smps_mode, sta->addr); smps = WMI_PEER_SMPS_PS_NONE; break; } @@ -4108,15 +4313,6 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, arsta->smps = smps; } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - /* FIXME: Not implemented. Probably the only way to do it would - * be to re-assoc the peer. */ - changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED; - ath10k_dbg(ATH10K_DBG_MAC, - "mac sta rc update for %pM: changing supported rates not implemented\n", - sta->addr); - } - arsta->changed |= changed; spin_unlock_bh(&ar->data_lock); @@ -4154,10 +4350,11 @@ 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, - .channel_switch_beacon = ath10k_channel_switch_beacon, .sta_rc_update = ath10k_sta_rc_update, .get_tsf = ath10k_get_tsf, #ifdef CONFIG_PM @@ -4503,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) | @@ -4516,7 +4725,6 @@ 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_SPECTRUM_MGMT; @@ -4570,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: %i\n", ret); + 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 9d242d801d9d..d0004d59c97e 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) = { @@ -346,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; @@ -442,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; } @@ -490,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; @@ -588,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; } @@ -747,17 +762,21 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, 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 = src_ring->nentries_mask; - unsigned int sw_index = src_ring->sw_index; - unsigned int write_index = src_ring->write_index; - int err, i; + 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 unlock; + goto err; } for (i = 0; i < n_items - 1; i++) { @@ -774,7 +793,7 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, items[i].transfer_id, CE_SEND_FLAG_GATHER); if (err) - goto unlock; + goto err; } /* `i` is equal to `n_items -1` after for() */ @@ -792,10 +811,15 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, items[i].transfer_id, 0); if (err) - goto unlock; + goto err; + + spin_unlock_bh(&ar_pci->ce_lock); + return 0; + +err: + for (; i > 0; i--) + __ath10k_ce_send_revert(ce_pipe); - err = 0; -unlock: spin_unlock_bh(&ar_pci->ce_lock); return err; } @@ -803,6 +827,9 @@ unlock: 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); } @@ -854,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; /* @@ -880,7 +909,7 @@ 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)); @@ -938,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; @@ -997,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, @@ -1098,6 +1131,8 @@ 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); @@ -1233,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) @@ -1252,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) @@ -1697,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) { @@ -1741,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) { @@ -1767,13 +1815,32 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(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) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret = 0; u32 val; - ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n"); + ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n"); ret = ath10k_do_pci_wake(ar); if (ret) { @@ -1801,7 +1868,7 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) msleep(100); /* clear fw indicator */ - ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0); + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); /* clear target LF timer interrupts */ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + @@ -1826,6 +1893,8 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) 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); @@ -1934,7 +2003,9 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) 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; @@ -1952,23 +2023,52 @@ 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 (notably after a firmware - * crash) so fall back to cold reset if necessary. + * Warm reset doesn't always work though so fall back to cold reset may + * be necessary. */ - ret = __ath10k_pci_hif_power_up(ar, false); + ret = ath10k_pci_hif_power_up_warm(ar); if (ret) { - ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n", + 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", @@ -1984,12 +2084,14 @@ 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_ce_deinit(ar); ath10k_pci_warm_reset(ar); - ath10k_pci_ce_deinit(ar); if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); } @@ -2137,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; @@ -2148,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); @@ -2385,33 +2483,69 @@ 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; @@ -2422,6 +2556,8 @@ 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", @@ -2453,6 +2589,9 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) } ath10k_do_pci_sleep(ar); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n"); + return 0; } @@ -2484,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) @@ -2503,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); @@ -2516,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); @@ -2594,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: @@ -2626,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; @@ -2636,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); @@ -2680,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 b43fdb4f7319..dfdebb4157aa 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -189,9 +189,6 @@ struct ath10k_pci { 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 0541dd939ce9..82669a77e553 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -100,189 +100,6 @@ exit: wake_up(&htt->empty_tx_wq); } -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->vht_flag |= RX_VHT_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; - - if (info->rate.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { - /* TSF available only in 32-bit */ - status->mactime = info->tsf & 0xffffffff; - status->flag |= RX_FLAG_MACTIME_END; - } - - 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 %i\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->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, info->fcs_err); - 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, const u8 *addr) { diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h index 356dc9c04c9e..aee3e20058f8 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 cb1f7b5bcf4c..4b7782a529ac 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -639,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; @@ -648,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); @@ -659,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); @@ -957,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, @@ -1362,13 +1378,10 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct sk_buff *bcn; int ret, vdev_id = 0; - ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n"); - 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++) { @@ -1385,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), @@ -1439,6 +1447,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) 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, @@ -1448,6 +1457,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ATH10K_SKB_CB(bcn)->paddr); if (ret) { ath10k_warn("failed to map beacon: %d\n", ret); + dev_kfree_skb_any(bcn); goto skip; } @@ -2365,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; @@ -2393,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; @@ -2418,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) { @@ -3456,8 +3507,9 @@ 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); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f51d5ca0141f..e93df2c10413 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; @@ -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 @@ -2295,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, @@ -2682,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 */ @@ -2738,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 */ @@ -2795,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 */ @@ -2804,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; /* @@ -2818,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 { @@ -4196,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, 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 *); |