diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath11k')
21 files changed, 1415 insertions, 349 deletions
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 920abce9053a..5cbba9a8b6ba 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -874,11 +874,11 @@ static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab) ab->pci.msi.ep_base_data = int_prop + 32; for (i = 0; i < ab->pci.msi.config->total_vectors; i++) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, i); - if (!res) - return -ENODEV; + ret = platform_get_irq(pdev, i); + if (ret < 0) + return ret; - ab->pci.msi.irqs[i] = res->start; + ab->pci.msi.irqs[i] = ret; } set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); @@ -1078,6 +1078,12 @@ static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab) struct iommu_domain *iommu; size_t unmapped_size; + /* Chipsets not requiring MSA would have not initialized + * MSA resources, return success in such cases. + */ + if (!ab->hw_params.fixed_fw_mem) + return 0; + if (ab_ahb->fw.use_tz) return 0; @@ -1174,7 +1180,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) * to a new space for accessing them. */ ab->mem_ce = ioremap(ce_remap->base, ce_remap->size); - if (IS_ERR(ab->mem_ce)) { + if (!ab->mem_ce) { dev_err(&pdev->dev, "ce ioremap error\n"); ret = -ENOMEM; goto err_core_free; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 75fdbe4ef83a..b1b90bd34d67 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -116,7 +116,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tcl_ring_retry = true, .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, - .ftm_responder = true, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -199,7 +198,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, - .ftm_responder = true, }, { .name = "qca6390 hw2.0", @@ -284,7 +282,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, - .ftm_responder = false, }, { .name = "qcn9074 hw1.0", @@ -366,7 +363,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, - .ftm_responder = true, }, { .name = "wcn6855 hw2.0", @@ -451,7 +447,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, - .ftm_responder = false, }, { .name = "wcn6855 hw2.1", @@ -534,7 +529,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = true, - .ftm_responder = false, }, { .name = "wcn6750 hw1.0", @@ -599,7 +593,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .current_cc_support = true, .dbr_debug_support = false, .global_reset = false, - .bios_sar_capa = NULL, + .bios_sar_capa = &ath11k_hw_sar_capa_wcn6855, .m3_fw_support = false, .fixed_bdf_addr = false, .fixed_mem_region = false, @@ -615,7 +609,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE_WCN6750, .smp2p_wow_exit = true, .support_fw_mac_sequence = true, - .ftm_responder = false, }, { .hw_rev = ATH11K_HW_IPQ5018_HW10, @@ -695,7 +688,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .tx_ring_size = DP_TCL_DATA_RING_SIZE, .smp2p_wow_exit = false, .support_fw_mac_sequence = false, - .ftm_responder = true, }, }; diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index 2107ec05d14f..5536e8642331 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -26,13 +26,13 @@ int ath11k_dbring_validate_buffer(struct ath11k *ar, void *buffer, u32 size) static void ath11k_dbring_fill_magic_value(struct ath11k *ar, void *buffer, u32 size) { - u32 *temp; - int idx; - - size = size >> 2; + /* memset32 function fills buffer payload with the ATH11K_DB_MAGIC_VALUE + * and the variable size is expected to be the number of u32 values + * to be stored, not the number of bytes. + */ + size = size / sizeof(u32); - for (idx = 0, temp = buffer; idx < size; idx++, temp++) - *temp++ = ATH11K_DB_MAGIC_VALUE; + memset32(buffer, ATH11K_DB_MAGIC_VALUE, size); } static int ath11k_dbring_bufs_replenish(struct ath11k *ar, diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h index 2b97cbbd28cb..0bbd58a380de 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h @@ -143,7 +143,8 @@ enum htt_tx_pdev_underrun_enum { /* Bytes stored in little endian order */ /* Length should be multiple of DWORD */ struct htt_stats_string_tlv { - u32 data[0]; /* Can be variable length */ + /* Can be variable length */ + DECLARE_FLEX_ARRAY(u32, data); } __packed; #define HTT_STATS_MAC_ID GENMASK(7, 0) @@ -205,27 +206,32 @@ struct htt_tx_pdev_stats_cmn_tlv { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_pdev_stats_urrn_tlv_v { - u32 urrn_stats[0]; /* HTT_TX_PDEV_MAX_URRN_STATS */ + /* HTT_TX_PDEV_MAX_URRN_STATS */ + DECLARE_FLEX_ARRAY(u32, urrn_stats); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_pdev_stats_flush_tlv_v { - u32 flush_errs[0]; /* HTT_TX_PDEV_MAX_FLUSH_REASON_STATS */ + /* HTT_TX_PDEV_MAX_FLUSH_REASON_STATS */ + DECLARE_FLEX_ARRAY(u32, flush_errs); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_pdev_stats_sifs_tlv_v { - u32 sifs_status[0]; /* HTT_TX_PDEV_MAX_SIFS_BURST_STATS */ + /* HTT_TX_PDEV_MAX_SIFS_BURST_STATS */ + DECLARE_FLEX_ARRAY(u32, sifs_status); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_pdev_stats_phy_err_tlv_v { - u32 phy_errs[0]; /* HTT_TX_PDEV_MAX_PHY_ERR_STATS */ + /* HTT_TX_PDEV_MAX_PHY_ERR_STATS */ + DECLARE_FLEX_ARRAY(u32, phy_errs); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_pdev_stats_sifs_hist_tlv_v { - u32 sifs_hist_status[0]; /* HTT_TX_PDEV_SIFS_BURST_HIST_STATS */ + /* HTT_TX_PDEV_SIFS_BURST_HIST_STATS */ + DECLARE_FLEX_ARRAY(u32, sifs_hist_status); }; struct htt_tx_pdev_stats_tx_ppdu_stats_tlv_v { @@ -590,20 +596,20 @@ struct htt_tx_hwq_difs_latency_stats_tlv_v { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_hwq_cmd_result_stats_tlv_v { - /* Histogram of sched cmd result */ - u32 cmd_result[0]; /* HTT_TX_HWQ_MAX_CMD_RESULT_STATS */ + /* Histogram of sched cmd result, HTT_TX_HWQ_MAX_CMD_RESULT_STATS */ + DECLARE_FLEX_ARRAY(u32, cmd_result); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_hwq_cmd_stall_stats_tlv_v { - /* Histogram of various pause conitions */ - u32 cmd_stall_status[0]; /* HTT_TX_HWQ_MAX_CMD_STALL_STATS */ + /* Histogram of various pause conitions, HTT_TX_HWQ_MAX_CMD_STALL_STATS */ + DECLARE_FLEX_ARRAY(u32, cmd_stall_status); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_hwq_fes_result_stats_tlv_v { - /* Histogram of number of user fes result */ - u32 fes_result[0]; /* HTT_TX_HWQ_MAX_FES_RESULT_STATS */ + /* Histogram of number of user fes result, HTT_TX_HWQ_MAX_FES_RESULT_STATS */ + DECLARE_FLEX_ARRAY(u32, fes_result); }; /* NOTE: Variable length TLV, use length spec to infer array size @@ -635,8 +641,8 @@ struct htt_tx_hwq_tried_mpdu_cnt_hist_tlv_v { * #define WAL_TXOP_USED_HISTOGRAM_INTERVAL 1000 ( 1 ms ) */ struct htt_tx_hwq_txop_used_cnt_hist_tlv_v { - /* Histogram of txop used cnt */ - u32 txop_used_cnt_hist[0]; /* HTT_TX_HWQ_TXOP_USED_CNT_HIST */ + /* Histogram of txop used cnt, HTT_TX_HWQ_TXOP_USED_CNT_HIST */ + DECLARE_FLEX_ARRAY(u32, txop_used_cnt_hist); }; /* == TX SELFGEN STATS == */ @@ -804,17 +810,20 @@ struct htt_tx_pdev_mpdu_stats_tlv { /* == TX SCHED STATS == */ /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_sched_txq_cmd_posted_tlv_v { - u32 sched_cmd_posted[0]; /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */ + /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */ + DECLARE_FLEX_ARRAY(u32, sched_cmd_posted); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_sched_txq_cmd_reaped_tlv_v { - u32 sched_cmd_reaped[0]; /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */ + /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */ + DECLARE_FLEX_ARRAY(u32, sched_cmd_reaped); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_sched_txq_sched_order_su_tlv_v { - u32 sched_order_su[0]; /* HTT_TX_PDEV_NUM_SCHED_ORDER_LOG */ + /* HTT_TX_PDEV_NUM_SCHED_ORDER_LOG */ + DECLARE_FLEX_ARRAY(u32, sched_order_su); }; enum htt_sched_txq_sched_ineligibility_tlv_enum { @@ -842,7 +851,7 @@ enum htt_sched_txq_sched_ineligibility_tlv_enum { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_sched_txq_sched_ineligibility_tlv_v { /* indexed by htt_sched_txq_sched_ineligibility_tlv_enum */ - u32 sched_ineligibility[0]; + DECLARE_FLEX_ARRAY(u32, sched_ineligibility); }; #define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID GENMASK(7, 0) @@ -888,18 +897,20 @@ struct htt_stats_tx_sched_cmn_tlv { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_tqm_gen_mpdu_stats_tlv_v { - u32 gen_mpdu_end_reason[0]; /* HTT_TX_TQM_MAX_GEN_MPDU_END_REASON */ + /* HTT_TX_TQM_MAX_GEN_MPDU_END_REASON */ + DECLARE_FLEX_ARRAY(u32, gen_mpdu_end_reason); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_tqm_list_mpdu_stats_tlv_v { - u32 list_mpdu_end_reason[0]; /* HTT_TX_TQM_MAX_LIST_MPDU_END_REASON */ + /* HTT_TX_TQM_MAX_LIST_MPDU_END_REASON */ + DECLARE_FLEX_ARRAY(u32, list_mpdu_end_reason); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_tx_tqm_list_mpdu_cnt_tlv_v { - u32 list_mpdu_cnt_hist[0]; - /* HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS */ + /* HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS */ + DECLARE_FLEX_ARRAY(u32, list_mpdu_cnt_hist); }; struct htt_tx_tqm_pdev_stats_tlv_v { @@ -1098,7 +1109,7 @@ struct htt_tx_de_compl_stats_tlv { * ENTRIES_PER_BIN_COUNT) */ struct htt_tx_de_fw2wbm_ring_full_hist_tlv { - u32 fw2wbm_ring_full_hist[0]; + DECLARE_FLEX_ARRAY(u32, fw2wbm_ring_full_hist); }; struct htt_tx_de_cmn_stats_tlv { @@ -1151,7 +1162,7 @@ struct htt_ring_if_cmn_tlv { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_sfm_client_user_tlv_v { /* Number of DWORDS used per user and per client */ - u32 dwords_used_by_user_n[0]; + DECLARE_FLEX_ARRAY(u32, dwords_used_by_user_n); }; struct htt_sfm_client_tlv { @@ -1436,12 +1447,14 @@ struct htt_rx_soc_fw_stats_tlv { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_rx_soc_fw_refill_ring_empty_tlv_v { - u32 refill_ring_empty_cnt[0]; /* HTT_RX_STATS_REFILL_MAX_RING */ + /* HTT_RX_STATS_REFILL_MAX_RING */ + DECLARE_FLEX_ARRAY(u32, refill_ring_empty_cnt); }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_rx_soc_fw_refill_ring_num_refill_tlv_v { - u32 refill_ring_num_refill[0]; /* HTT_RX_STATS_REFILL_MAX_RING */ + /* HTT_RX_STATS_REFILL_MAX_RING */ + DECLARE_FLEX_ARRAY(u32, refill_ring_num_refill); }; /* RXDMA error code from WBM released packets */ @@ -1473,7 +1486,7 @@ enum htt_rx_rxdma_error_code_enum { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_rx_soc_fw_refill_ring_num_rxdma_err_tlv_v { - u32 rxdma_err[0]; /* HTT_RX_RXDMA_MAX_ERR_CODE */ + DECLARE_FLEX_ARRAY(u32, rxdma_err); /* HTT_RX_RXDMA_MAX_ERR_CODE */ }; /* REO error code from WBM released packets */ @@ -1505,7 +1518,7 @@ enum htt_rx_reo_error_code_enum { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_rx_soc_fw_refill_ring_num_reo_err_tlv_v { - u32 reo_err[0]; /* HTT_RX_REO_MAX_ERR_CODE */ + DECLARE_FLEX_ARRAY(u32, reo_err); /* HTT_RX_REO_MAX_ERR_CODE */ }; /* == RX PDEV STATS == */ @@ -1622,13 +1635,13 @@ struct htt_rx_pdev_fw_stats_phy_err_tlv { /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_rx_pdev_fw_ring_mpdu_err_tlv_v { /* Num error MPDU for each RxDMA error type */ - u32 fw_ring_mpdu_err[0]; /* HTT_RX_STATS_RXDMA_MAX_ERR */ + DECLARE_FLEX_ARRAY(u32, fw_ring_mpdu_err); /* HTT_RX_STATS_RXDMA_MAX_ERR */ }; /* NOTE: Variable length TLV, use length spec to infer array size */ struct htt_rx_pdev_fw_mpdu_drop_tlv_v { /* Num MPDU dropped */ - u32 fw_mpdu_drop[0]; /* HTT_RX_STATS_FW_DROP_REASON_MAX */ + DECLARE_FLEX_ARRAY(u32, fw_mpdu_drop); /* HTT_RX_STATS_FW_DROP_REASON_MAX */ }; #define HTT_PDEV_CCA_STATS_TX_FRAME_INFO_PRESENT (0x1) diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index f5156a7fbdd7..d070bcb3fe24 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -36,6 +36,7 @@ void ath11k_dp_peer_cleanup(struct ath11k *ar, int vdev_id, const u8 *addr) } ath11k_peer_rx_tid_cleanup(ar, peer); + peer->dp_setup_done = false; crypto_free_shash(peer->tfm_mmic); spin_unlock_bh(&ab->base_lock); } @@ -72,7 +73,8 @@ int ath11k_dp_peer_setup(struct ath11k *ar, int vdev_id, const u8 *addr) ret = ath11k_peer_rx_frag_setup(ar, addr, vdev_id); if (ret) { ath11k_warn(ab, "failed to setup rx defrag context\n"); - return ret; + tid--; + goto peer_clean; } /* TODO: Setup other peer specific resource used in data path */ diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index be9eafc872b3..d04f78ab6b37 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -214,7 +214,7 @@ struct ath11k_pdev_dp { #define DP_REO_REINJECT_RING_SIZE 32 #define DP_RX_RELEASE_RING_SIZE 1024 #define DP_REO_EXCEPTION_RING_SIZE 128 -#define DP_REO_CMD_RING_SIZE 128 +#define DP_REO_CMD_RING_SIZE 256 #define DP_REO_STATUS_RING_SIZE 2048 #define DP_RXDMA_BUF_RING_SIZE 4096 #define DP_RXDMA_REFILL_RING_SIZE 2048 @@ -303,12 +303,16 @@ struct ath11k_dp { #define HTT_TX_WBM_COMP_STATUS_OFFSET 8 +#define HTT_INVALID_PEER_ID 0xffff + /* HTT tx completion is overlaid in wbm_release_ring */ #define HTT_TX_WBM_COMP_INFO0_STATUS GENMASK(12, 9) #define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON GENMASK(16, 13) #define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON GENMASK(16, 13) #define HTT_TX_WBM_COMP_INFO1_ACK_RSSI GENMASK(31, 24) +#define HTT_TX_WBM_COMP_INFO2_SW_PEER_ID GENMASK(15, 0) +#define HTT_TX_WBM_COMP_INFO2_VALID BIT(21) struct htt_tx_wbm_completion { u32 info0; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index b65a84a88264..f67ce62b2b48 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -389,10 +389,10 @@ int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id, goto fail_free_skb; spin_lock_bh(&rx_ring->idr_lock); - buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0, - rx_ring->bufs_max * 3, GFP_ATOMIC); + buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 1, + (rx_ring->bufs_max * 3) + 1, GFP_ATOMIC); spin_unlock_bh(&rx_ring->idr_lock); - if (buf_id < 0) + if (buf_id <= 0) goto fail_dma_unmap; desc = ath11k_hal_srng_src_get_next_entry(ab, srng); @@ -435,7 +435,6 @@ fail_free_skb: static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, struct dp_rxdma_ring *rx_ring) { - struct ath11k_pdev_dp *dp = &ar->dp; struct sk_buff *skb; int buf_id; @@ -453,28 +452,6 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, idr_destroy(&rx_ring->bufs_idr); spin_unlock_bh(&rx_ring->idr_lock); - /* if rxdma1_enable is false, mon_status_refill_ring - * isn't setup, so don't clean. - */ - if (!ar->ab->hw_params.rxdma1_enable) - return 0; - - rx_ring = &dp->rx_mon_status_refill_ring[0]; - - spin_lock_bh(&rx_ring->idr_lock); - idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { - idr_remove(&rx_ring->bufs_idr, buf_id); - /* XXX: Understand where internal driver does this dma_unmap - * of rxdma_buffer. - */ - dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr, - skb->len + skb_tailroom(skb), DMA_BIDIRECTIONAL); - dev_kfree_skb_any(skb); - } - - idr_destroy(&rx_ring->bufs_idr); - spin_unlock_bh(&rx_ring->idr_lock); - return 0; } @@ -691,13 +668,18 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab) struct ath11k_dp *dp = &ab->dp; struct dp_reo_cmd *cmd, *tmp; struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache; + struct dp_rx_tid *rx_tid; spin_lock_bh(&dp->reo_cmd_lock); list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { list_del(&cmd->list); - dma_unmap_single(ab->dev, cmd->data.paddr, - cmd->data.size, DMA_BIDIRECTIONAL); - kfree(cmd->data.vaddr); + rx_tid = &cmd->data; + if (rx_tid->vaddr) { + dma_unmap_single(ab->dev, rx_tid->paddr, + rx_tid->size, DMA_BIDIRECTIONAL); + kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; + } kfree(cmd); } @@ -705,9 +687,13 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab) &dp->reo_cmd_cache_flush_list, list) { list_del(&cmd_cache->list); dp->reo_cmd_cache_flush_count--; - dma_unmap_single(ab->dev, cmd_cache->data.paddr, - cmd_cache->data.size, DMA_BIDIRECTIONAL); - kfree(cmd_cache->data.vaddr); + rx_tid = &cmd_cache->data; + if (rx_tid->vaddr) { + dma_unmap_single(ab->dev, rx_tid->paddr, + rx_tid->size, DMA_BIDIRECTIONAL); + kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; + } kfree(cmd_cache); } spin_unlock_bh(&dp->reo_cmd_lock); @@ -721,10 +707,12 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx, if (status != HAL_REO_CMD_SUCCESS) ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n", rx_tid->tid, status); - - dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size, - DMA_BIDIRECTIONAL); - kfree(rx_tid->vaddr); + if (rx_tid->vaddr) { + dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size, + DMA_BIDIRECTIONAL); + kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; + } } static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, @@ -763,6 +751,7 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, DMA_BIDIRECTIONAL); kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; } } @@ -815,6 +804,7 @@ free_desc: dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, DMA_BIDIRECTIONAL); kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; } void ath11k_peer_rx_tid_delete(struct ath11k *ar, @@ -827,6 +817,8 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar, if (!rx_tid->active) return; + rx_tid->active = false; + cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; cmd.addr_lo = lower_32_bits(rx_tid->paddr); cmd.addr_hi = upper_32_bits(rx_tid->paddr); @@ -841,9 +833,11 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar, dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size, DMA_BIDIRECTIONAL); kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; } - rx_tid->active = false; + rx_tid->paddr = 0; + rx_tid->size = 0; } static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab, @@ -990,6 +984,7 @@ static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab, dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, DMA_BIDIRECTIONAL); kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; rx_tid->active = false; @@ -1014,7 +1009,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, peer = ath11k_peer_find(ab, vdev_id, peer_mac); if (!peer) { - ath11k_warn(ab, "failed to find the peer to set up rx tid\n"); + ath11k_warn(ab, "failed to find the peer %pM to set up rx tid\n", + peer_mac); spin_unlock_bh(&ab->base_lock); return -ENOENT; } @@ -1027,7 +1023,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, ba_win_sz, ssn, true); spin_unlock_bh(&ab->base_lock); if (ret) { - ath11k_warn(ab, "failed to update reo for rx tid %d\n", tid); + ath11k_warn(ab, "failed to update reo for peer %pM rx tid %d\n: %d", + peer_mac, tid, ret); return ret; } @@ -1035,8 +1032,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, peer_mac, paddr, tid, 1, ba_win_sz); if (ret) - ath11k_warn(ab, "failed to send wmi command to update rx reorder queue, tid :%d (%d)\n", - tid, ret); + ath11k_warn(ab, "failed to send wmi rx reorder queue for peer %pM tid %d: %d\n", + peer_mac, tid, ret); return ret; } @@ -1069,6 +1066,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, ret = dma_mapping_error(ab->dev, paddr); if (ret) { spin_unlock_bh(&ab->base_lock); + ath11k_warn(ab, "failed to setup dma map for peer %pM rx tid %d: %d\n", + peer_mac, tid, ret); goto err_mem_free; } @@ -1082,15 +1081,16 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, paddr, tid, 1, ba_win_sz); if (ret) { - ath11k_warn(ar->ab, "failed to setup rx reorder queue, tid :%d (%d)\n", - tid, ret); + ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n", + peer_mac, tid, ret); ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid); } return ret; err_mem_free: - kfree(vaddr); + kfree(rx_tid->vaddr); + rx_tid->vaddr = NULL; return ret; } @@ -2665,6 +2665,9 @@ try_again: cookie); mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); + if (unlikely(buf_id == 0)) + continue; + ar = ab->pdevs[mac_id].ar; rx_ring = &ar->dp.rx_refill_buf_ring; spin_lock_bh(&rx_ring->idr_lock); @@ -3029,39 +3032,51 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, spin_lock_bh(&rx_ring->idr_lock); skb = idr_find(&rx_ring->bufs_idr, buf_id); + spin_unlock_bh(&rx_ring->idr_lock); + if (!skb) { ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n", buf_id); - spin_unlock_bh(&rx_ring->idr_lock); pmon->buf_state = DP_MON_STATUS_REPLINISH; goto move_next; } - idr_remove(&rx_ring->bufs_idr, buf_id); - spin_unlock_bh(&rx_ring->idr_lock); - rxcb = ATH11K_SKB_RXCB(skb); - dma_unmap_single(ab->dev, rxcb->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(ab->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); tlv = (struct hal_tlv_hdr *)skb->data; if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_STATUS_BUFFER_DONE) { - ath11k_warn(ab, "mon status DONE not set %lx\n", + ath11k_warn(ab, "mon status DONE not set %lx, buf_id %d\n", FIELD_GET(HAL_TLV_HDR_TAG, - tlv->tl)); - dev_kfree_skb_any(skb); + tlv->tl), buf_id); + /* If done status is missing, hold onto status + * ring until status is done for this status + * ring buffer. + * Keep HP in mon_status_ring unchanged, + * and break from here. + * Check status for same buffer for next time + */ pmon->buf_state = DP_MON_STATUS_NO_DMA; - goto move_next; + break; } + spin_lock_bh(&rx_ring->idr_lock); + idr_remove(&rx_ring->bufs_idr, buf_id); + spin_unlock_bh(&rx_ring->idr_lock); if (ab->hw_params.full_monitor_mode) { ath11k_dp_rx_mon_update_status_buf_state(pmon, tlv); if (paddr == pmon->mon_status_paddr) pmon->buf_state = DP_MON_STATUS_MATCH; } + + dma_unmap_single(ab->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + __skb_queue_tail(skb_list, skb); } else { pmon->buf_state = DP_MON_STATUS_REPLINISH; @@ -3117,8 +3132,11 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id int i; tfm = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(tfm)) + if (IS_ERR(tfm)) { + ath11k_warn(ab, "failed to allocate michael_mic shash: %ld\n", + PTR_ERR(tfm)); return PTR_ERR(tfm); + } spin_lock_bh(&ab->base_lock); @@ -3138,6 +3156,7 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id } peer->tfm_mmic = tfm; + peer->dp_setup_done = true; spin_unlock_bh(&ab->base_lock); return 0; @@ -3583,6 +3602,13 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, ret = -ENOENT; goto out_unlock; } + if (!peer->dp_setup_done) { + ath11k_warn(ab, "The peer %pM [%d] has uninitialized datapath\n", + peer->addr, peer_id); + ret = -ENOENT; + goto out_unlock; + } + rx_tid = &peer->rx_tid[tid]; if ((!skb_queue_empty(&rx_tid->rx_frags) && seqno != rx_tid->cur_sn) || @@ -3598,7 +3624,7 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, goto out_unlock; } - if (frag_no > __fls(rx_tid->rx_frag_bitmap)) + if (!rx_tid->rx_frag_bitmap || (frag_no > __fls(rx_tid->rx_frag_bitmap))) __skb_queue_tail(&rx_tid->rx_frags, msdu); else ath11k_dp_rx_h_sort_frags(ar, &rx_tid->rx_frags, msdu); diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 8afbba236935..08a28464eb7a 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -316,10 +316,12 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, struct dp_tx_ring *tx_ring, struct ath11k_dp_htt_wbm_tx_status *ts) { + struct ieee80211_tx_status status = { 0 }; struct sk_buff *msdu; struct ieee80211_tx_info *info; struct ath11k_skb_cb *skb_cb; struct ath11k *ar; + struct ath11k_peer *peer; spin_lock(&tx_ring->tx_idr_lock); msdu = idr_remove(&tx_ring->txbuf_idr, ts->msdu_id); @@ -341,6 +343,11 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + if (!skb_cb->vif) { + dev_kfree_skb_any(msdu); + return; + } + memset(&info->status, 0, sizeof(info->status)); if (ts->acked) { @@ -355,7 +362,23 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, } } - ieee80211_tx_status(ar->hw, msdu); + spin_lock_bh(&ab->base_lock); + peer = ath11k_peer_find_by_id(ab, ts->peer_id); + if (!peer || !peer->sta) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "dp_tx: failed to find the peer with peer_id %d\n", + ts->peer_id); + spin_unlock_bh(&ab->base_lock); + dev_kfree_skb_any(msdu); + return; + } + spin_unlock_bh(&ab->base_lock); + + status.sta = peer->sta; + status.info = info; + status.skb = msdu; + + ieee80211_tx_status_ext(ar->hw, &status); } static void @@ -379,7 +402,15 @@ ath11k_dp_tx_process_htt_tx_complete(struct ath11k_base *ab, ts.msdu_id = msdu_id; ts.ack_rssi = FIELD_GET(HTT_TX_WBM_COMP_INFO1_ACK_RSSI, status_desc->info1); + + if (FIELD_GET(HTT_TX_WBM_COMP_INFO2_VALID, status_desc->info2)) + ts.peer_id = FIELD_GET(HTT_TX_WBM_COMP_INFO2_SW_PEER_ID, + status_desc->info2); + else + ts.peer_id = HTT_INVALID_PEER_ID; + ath11k_dp_tx_htt_tx_complete_buf(ab, tx_ring, &ts); + break; case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ: case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT: diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.h b/drivers/net/wireless/ath/ath11k/dp_tx.h index e87d65bfbf06..68a21ea9b934 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.h +++ b/drivers/net/wireless/ath/ath11k/dp_tx.h @@ -13,6 +13,7 @@ struct ath11k_dp_htt_wbm_tx_status { u32 msdu_id; bool acked; int ack_rssi; + u16 peer_id; }; void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts); diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index 7f39c6fb7408..bb1d40034aa8 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -865,6 +865,12 @@ ath11k_hal_rx_populate_mu_user_info(void *rx_tlv, struct hal_rx_mon_ppdu_info *p ath11k_hal_rx_populate_byte_count(rx_tlv, ppdu_info, rx_user_status); } +static u16 ath11k_hal_rx_mpduinfo_get_peerid(struct ath11k_base *ab, + struct hal_rx_mpdu_info *mpdu_info) +{ + return ab->hw_params.hw_ops->mpdu_info_get_peerid(mpdu_info); +} + static enum hal_rx_mon_status ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab, struct hal_rx_mon_ppdu_info *ppdu_info, @@ -1023,7 +1029,7 @@ ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab, info1 = __le32_to_cpu(vht_sig->info1); ppdu_info->ldpc = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING, - info0); + info1); ppdu_info->mcs = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO1_MCS, info1); gi_setting = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO1_GI_SETTING, @@ -1446,7 +1452,7 @@ ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab, * PHYRX_OTHER_RECEIVE_INFO TLV. */ ppdu_info->rssi_comb = - FIELD_GET(HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB, + FIELD_GET(HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB, __le32_to_cpu(rssi->info0)); if (db2dbm) { @@ -1459,9 +1465,11 @@ ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab, break; } case HAL_RX_MPDU_START: { + struct hal_rx_mpdu_info *mpdu_info = + (struct hal_rx_mpdu_info *)tlv_data; u16 peer_id; - peer_id = ab->hw_params.hw_ops->mpdu_info_get_peerid(tlv_data); + peer_id = ath11k_hal_rx_mpduinfo_get_peerid(ab, mpdu_info); if (peer_id) ppdu_info->peer_id = peer_id; break; diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.h b/drivers/net/wireless/ath/ath11k/hal_rx.h index f6bae07abfd3..61bd8416c4fd 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.h +++ b/drivers/net/wireless/ath/ath11k/hal_rx.h @@ -385,7 +385,7 @@ struct hal_rx_he_sig_b2_ofdma_info { __le32 info0; } __packed; -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8) +#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB GENMASK(15, 8) #define HAL_RX_PHYRX_RSSI_PREAMBLE_PRI20 GENMASK(7, 0) @@ -405,7 +405,7 @@ struct hal_rx_phyrx_rssi_legacy_info { #define HAL_RX_MPDU_INFO_INFO0_PEERID_WCN6855 GENMASK(15, 0) #define HAL_RX_MPDU_INFO_INFO1_MPDU_LEN GENMASK(13, 0) -struct hal_rx_mpdu_info { +struct hal_rx_mpdu_info_ipq8074 { __le32 rsvd0; __le32 info0; __le32 rsvd1[11]; @@ -413,12 +413,28 @@ struct hal_rx_mpdu_info { __le32 rsvd2[9]; } __packed; +struct hal_rx_mpdu_info_qcn9074 { + __le32 rsvd0[10]; + __le32 info0; + __le32 rsvd1[2]; + __le32 info1; + __le32 rsvd2[9]; +} __packed; + struct hal_rx_mpdu_info_wcn6855 { __le32 rsvd0[8]; __le32 info0; __le32 rsvd1[14]; } __packed; +struct hal_rx_mpdu_info { + union { + struct hal_rx_mpdu_info_ipq8074 ipq8074; + struct hal_rx_mpdu_info_qcn9074 qcn9074; + struct hal_rx_mpdu_info_wcn6855 wcn6855; + } u; +} __packed; + #define HAL_RX_PPDU_END_DURATION GENMASK(23, 0) struct hal_rx_ppdu_end_duration { __le32 rsvd0[9]; diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index ab8f0ccacc6b..eb995f9cf0fa 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -201,6 +201,7 @@ static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; + config->flag1 |= WMI_RSRC_CFG_FLAG1_ACK_RSSI; } static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, @@ -834,26 +835,35 @@ static void ath11k_hw_ipq5018_reo_setup(struct ath11k_base *ab) ring_hash_map); } -static u16 ath11k_hw_ipq8074_mpdu_info_get_peerid(u8 *tlv_data) +static u16 +ath11k_hw_ipq8074_mpdu_info_get_peerid(struct hal_rx_mpdu_info *mpdu_info) { u16 peer_id = 0; - struct hal_rx_mpdu_info *mpdu_info = - (struct hal_rx_mpdu_info *)tlv_data; peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID, - __le32_to_cpu(mpdu_info->info0)); + __le32_to_cpu(mpdu_info->u.ipq8074.info0)); return peer_id; } -static u16 ath11k_hw_wcn6855_mpdu_info_get_peerid(u8 *tlv_data) +static u16 +ath11k_hw_qcn9074_mpdu_info_get_peerid(struct hal_rx_mpdu_info *mpdu_info) +{ + u16 peer_id = 0; + + peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID, + __le32_to_cpu(mpdu_info->u.qcn9074.info0)); + + return peer_id; +} + +static u16 +ath11k_hw_wcn6855_mpdu_info_get_peerid(struct hal_rx_mpdu_info *mpdu_info) { u16 peer_id = 0; - struct hal_rx_mpdu_info_wcn6855 *mpdu_info = - (struct hal_rx_mpdu_info_wcn6855 *)tlv_data; peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID_WCN6855, - __le32_to_cpu(mpdu_info->info0)); + __le32_to_cpu(mpdu_info->u.wcn6855.info0)); return peer_id; } @@ -1041,7 +1051,7 @@ const struct ath11k_hw_ops qcn9074_ops = { .rx_desc_get_attention = ath11k_hw_qcn9074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload, .reo_setup = ath11k_hw_ipq8074_reo_setup, - .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, + .mpdu_info_get_peerid = ath11k_hw_qcn9074_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2, .get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector, @@ -1223,6 +1233,7 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = { ATH11K_RX_WBM_REL_RING_MASK_0, }, .reo_status = { + 0, 0, 0, ATH11K_REO_STATUS_RING_MASK_0, }, .rxdma2host = { diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 0be4e1232384..6a5dd2dbdb3a 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -224,7 +224,6 @@ struct ath11k_hw_params { u32 tx_ring_size; bool smp2p_wow_exit; bool support_fw_mac_sequence; - bool ftm_responder; }; struct ath11k_hw_ops { @@ -264,7 +263,7 @@ struct ath11k_hw_ops { struct rx_attention *(*rx_desc_get_attention)(struct hal_rx_desc *desc); u8 *(*rx_desc_get_msdu_payload)(struct hal_rx_desc *desc); void (*reo_setup)(struct ath11k_base *ab); - u16 (*mpdu_info_get_peerid)(u8 *tlv_data); + u16 (*mpdu_info_get_peerid)(struct hal_rx_mpdu_info *mpdu_info); bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc); u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc); u32 (*get_ring_selector)(struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 110a38cce0a7..1c93f1afccc5 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2699,6 +2699,117 @@ static int ath11k_setup_peer_smps(struct ath11k *ar, struct ath11k_vif *arvif, ath11k_smps_map[smps]); } +static bool ath11k_mac_set_he_txbf_conf(struct ath11k_vif *arvif) +{ + struct ath11k *ar = arvif->ar; + u32 param, value; + int ret; + + if (!arvif->vif->bss_conf.he_support) + return true; + + param = WMI_VDEV_PARAM_SET_HEMU_MODE; + value = 0; + if (arvif->vif->bss_conf.he_su_beamformer) { + value |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE); + if (arvif->vif->bss_conf.he_mu_beamformer && + arvif->vdev_type == WMI_VDEV_TYPE_AP) + value |= FIELD_PREP(HE_MODE_MU_TX_BFER, HE_MU_BFER_ENABLE); + } + + if (arvif->vif->type != NL80211_IFTYPE_MESH_POINT) { + value |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) | + FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE); + + if (arvif->vif->bss_conf.he_full_ul_mumimo) + value |= FIELD_PREP(HE_MODE_UL_MUMIMO, HE_UL_MUMIMO_ENABLE); + + if (arvif->vif->bss_conf.he_su_beamformee) + value |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE); + } + + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value); + if (ret) { + ath11k_warn(ar->ab, "failed to set vdev %d HE MU mode: %d\n", + arvif->vdev_id, ret); + return false; + } + + param = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; + value = FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) | + FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE, + HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE); + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + param, value); + if (ret) { + ath11k_warn(ar->ab, "failed to set vdev %d sounding mode: %d\n", + arvif->vdev_id, ret); + return false; + } + return true; +} + +static bool ath11k_mac_vif_recalc_sta_he_txbf(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta_he_cap *he_cap) +{ + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ieee80211_he_cap_elem he_cap_elem = {0}; + struct ieee80211_sta_he_cap *cap_band = NULL; + struct cfg80211_chan_def def; + u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE; + u32 hemode = 0; + int ret; + + if (!vif->bss_conf.he_support) + return true; + + if (vif->type != NL80211_IFTYPE_STATION) + return false; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return false; + + if (def.chan->band == NL80211_BAND_2GHZ) + cap_band = &ar->mac.iftype[NL80211_BAND_2GHZ][vif->type].he_cap; + else + cap_band = &ar->mac.iftype[NL80211_BAND_5GHZ][vif->type].he_cap; + + memcpy(&he_cap_elem, &cap_band->he_cap_elem, sizeof(he_cap_elem)); + + if (HECAP_PHY_SUBFME_GET(he_cap_elem.phy_cap_info)) { + if (HECAP_PHY_SUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE); + if (HECAP_PHY_MUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE); + } + + if (vif->type != NL80211_IFTYPE_MESH_POINT) { + hemode |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) | + FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE); + + if (HECAP_PHY_ULMUMIMO_GET(he_cap_elem.phy_cap_info)) + if (HECAP_PHY_ULMUMIMO_GET(he_cap->he_cap_elem.phy_cap_info)) + hemode |= FIELD_PREP(HE_MODE_UL_MUMIMO, + HE_UL_MUMIMO_ENABLE); + + if (FIELD_GET(HE_MODE_MU_TX_BFEE, hemode)) + hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE); + + if (FIELD_GET(HE_MODE_MU_TX_BFER, hemode)) + hemode |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE); + } + + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, hemode); + if (ret) { + ath11k_warn(ar->ab, "failed to submit vdev param txbf 0x%x: %d\n", + hemode, ret); + return false; + } + + return true; +} + static void ath11k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) @@ -2709,6 +2820,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_sta *ap_sta; struct ath11k_peer *peer; bool is_auth = false; + struct ieee80211_sta_he_cap he_cap; int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2726,6 +2838,9 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, return; } + /* he_cap here is updated at assoc success for sta mode only */ + he_cap = ap_sta->deflink.he_cap; + ath11k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false); rcu_read_unlock(); @@ -2753,6 +2868,12 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, return; } + if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { + ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", + arvif->vdev_id, bss_conf->bssid); + return; + } + WARN_ON(arvif->is_up); arvif->aid = vif->cfg.aid; @@ -3202,6 +3323,8 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ether_addr_copy(arvif->bssid, info->bssid); if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (info->enable_beacon) + ath11k_mac_set_he_txbf_conf(arvif); ath11k_control_beaconing(arvif, info); if (arvif->is_up && vif->bss_conf.he_support && @@ -3415,7 +3538,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_FTM_RESPONDER && arvif->ftm_responder != info->ftm_responder && - ar->ab->hw_params.ftm_responder && + test_bit(WMI_TLV_SERVICE_RTT, ar->ab->wmi_ab.svc_map) && (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT)) { arvif->ftm_responder = info->ftm_responder; @@ -3632,6 +3755,18 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, int i; u32 scan_timeout; + /* Firmwares advertising the support of triggering 11D algorithm + * on the scan results of a regular scan expects driver to send + * WMI_11D_SCAN_START_CMDID before sending WMI_START_SCAN_CMDID. + * With this feature, separate 11D scan can be avoided since + * regdomain can be determined with the scan results of the + * regular scan. + */ + if (ar->state_11d == ATH11K_11D_PREPARING && + test_bit(WMI_TLV_SERVICE_SUPPORT_11D_FOR_HOST_SCAN, + ar->ab->wmi_ab.svc_map)) + ath11k_mac_11d_scan_start(ar, arvif->vdev_id); + mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); @@ -3696,8 +3831,29 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, goto exit; } - for (i = 0; i < arg->num_chan; i++) - arg->chan_list[i] = req->channels[i]->center_freq; + for (i = 0; i < arg->num_chan; i++) { + if (test_bit(WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL, + ar->ab->wmi_ab.svc_map)) { + arg->chan_list[i] = + u32_encode_bits(req->channels[i]->center_freq, + WMI_SCAN_CONFIG_PER_CHANNEL_MASK); + + /* If NL80211_SCAN_FLAG_COLOCATED_6GHZ is set in scan + * flags, then scan all PSC channels in 6 GHz band and + * those non-PSC channels where RNR IE is found during + * the legacy 2.4/5 GHz scan. + * If NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set, + * then all channels in 6 GHz will be scanned. + */ + if (req->channels[i]->band == NL80211_BAND_6GHZ && + req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ && + !cfg80211_channel_is_psc(req->channels[i])) + arg->chan_list[i] |= + WMI_SCAN_CH_FLAG_SCAN_ONLY_IF_RNR_FOUND; + } else { + arg->chan_list[i] = req->channels[i]->center_freq; + } + } } if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { @@ -5360,6 +5516,43 @@ static __le16 ath11k_mac_setup_he_6ghz_cap(struct ath11k_pdev_cap *pcap, return cpu_to_le16(bcap->he_6ghz_capa); } +static void ath11k_mac_set_hemcsmap(struct ath11k *ar, + struct ath11k_pdev_cap *cap, + struct ieee80211_sta_he_cap *he_cap, + int band) +{ + u16 txmcs_map, rxmcs_map; + u32 i; + + rxmcs_map = 0; + txmcs_map = 0; + for (i = 0; i < 8; i++) { + if (i < ar->num_tx_chains && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + txmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + txmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < ar->num_rx_chains && + (ar->cfg_rx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + rxmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + rxmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + } + he_cap->he_mcs_nss_supp.rx_mcs_80 = + cpu_to_le16(rxmcs_map & 0xffff); + he_cap->he_mcs_nss_supp.tx_mcs_80 = + cpu_to_le16(txmcs_map & 0xffff); + he_cap->he_mcs_nss_supp.rx_mcs_160 = + cpu_to_le16(rxmcs_map & 0xffff); + he_cap->he_mcs_nss_supp.tx_mcs_160 = + cpu_to_le16(txmcs_map & 0xffff); + he_cap->he_mcs_nss_supp.rx_mcs_80p80 = + cpu_to_le16(rxmcs_map & 0xffff); + he_cap->he_mcs_nss_supp.tx_mcs_80p80 = + cpu_to_le16(txmcs_map & 0xffff); +} + static int ath11k_mac_copy_he_cap(struct ath11k *ar, struct ath11k_pdev_cap *cap, struct ieee80211_sband_iftype_data *data, @@ -5417,18 +5610,7 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, break; } - he_cap->he_mcs_nss_supp.rx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); - he_cap->he_mcs_nss_supp.rx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.rx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + ath11k_mac_set_hemcsmap(ar, cap, he_cap, band); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & @@ -6026,69 +6208,6 @@ ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif, } } -static u32 -ath11k_mac_prepare_he_mode(struct ath11k_pdev *pdev, u32 viftype) -{ - struct ath11k_pdev_cap *pdev_cap = &pdev->cap; - struct ath11k_band_cap *cap_band = NULL; - u32 *hecap_phy_ptr = NULL; - u32 hemode = 0; - - if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) - cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; - else - cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; - - hecap_phy_ptr = &cap_band->he_cap_phy_info[0]; - - hemode = FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE) | - FIELD_PREP(HE_MODE_SU_TX_BFER, HECAP_PHY_SUBFMR_GET(hecap_phy_ptr)) | - FIELD_PREP(HE_MODE_UL_MUMIMO, HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr)); - - /* TODO WDS and other modes */ - if (viftype == NL80211_IFTYPE_AP) { - hemode |= FIELD_PREP(HE_MODE_MU_TX_BFER, - HECAP_PHY_MUBFMR_GET(hecap_phy_ptr)) | - FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) | - FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE); - } else { - hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE); - } - - return hemode; -} - -static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar, - struct ath11k_vif *arvif) -{ - u32 param_id, param_value; - struct ath11k_base *ab = ar->ab; - int ret = 0; - - param_id = WMI_VDEV_PARAM_SET_HEMU_MODE; - param_value = ath11k_mac_prepare_he_mode(ar->pdev, arvif->vif->type); - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n", - arvif->vdev_id, ret, param_value); - return ret; - } - param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; - param_value = - FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) | - FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE, - HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE); - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d\n", - arvif->vdev_id, ret); - return ret; - } - return ret; -} - static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -6562,6 +6681,11 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", arvif->vdev_id); + ret = ath11k_spectral_vif_stop(arvif); + if (ret) + ath11k_warn(ab, "failed to stop spectral for vdev %i: %d\n", + arvif->vdev_id, ret); + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) ath11k_mac_11d_scan_stop(ar); @@ -6757,7 +6881,6 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, struct ath11k_base *ab = ar->ab; struct wmi_vdev_start_req_arg arg = {}; const struct cfg80211_chan_def *chandef = &ctx->def; - int he_support = arvif->vif->bss_conf.he_support; int ret = 0; lockdep_assert_held(&ar->conf_mutex); @@ -6798,15 +6921,6 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, spin_lock_bh(&ab->base_lock); arg.regdomain = ar->ab->dfs_region; spin_unlock_bh(&ab->base_lock); - - if (he_support) { - ret = ath11k_set_he_mu_sounding_mode(ar, arvif); - if (ret) { - ath11k_warn(ar->ab, "failed to set he mode vdev %i\n", - arg.vdev_id); - return ret; - } - } } arg.channel.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); @@ -9094,6 +9208,11 @@ static int __ath11k_mac_register(struct ath11k *ar) goto err_free_if_combs; } + if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI, + ar->ab->wmi_ab.svc_map)) + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); + ar->hw->queues = ATH11K_HW_MAX_QUEUES; ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN; ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1; @@ -9128,7 +9247,7 @@ static int __ath11k_mac_register(struct ath11k *ar) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); - if (ab->hw_params.ftm_responder) + if (test_bit(WMI_TLV_SERVICE_RTT, ar->ab->wmi_ab.svc_map)) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 86995e8dc913..a62ee05c5409 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -16,7 +16,7 @@ #include "pci.h" #include "pcic.h" -#define MHI_TIMEOUT_DEFAULT_MS 90000 +#define MHI_TIMEOUT_DEFAULT_MS 20000 #define RDDM_DUMP_SIZE 0x420000 static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 0aeef2948ff5..7b33731a50ee 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -540,7 +540,7 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) if (!ab->mem) { ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); ret = -EIO; - goto clear_master; + goto release_region; } ab->mem_ce = ab->mem; @@ -548,8 +548,6 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); return 0; -clear_master: - pci_clear_master(pdev); release_region: pci_release_region(pdev, ATH11K_PCI_BAR_NUM); disable_device: @@ -565,7 +563,6 @@ static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) pci_iounmap(pci_dev, ab->mem); ab->mem = NULL; - pci_clear_master(pci_dev); pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); if (pci_is_enabled(pci_dev)) pci_disable_device(pci_dev); @@ -1039,7 +1036,8 @@ module_exit(ath11k_pci_exit); MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); MODULE_LICENSE("Dual BSD/GPL"); -/* QCA639x 2.0 firmware files */ -MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); -MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); -MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); +/* firmware files */ +MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/*"); +MODULE_FIRMWARE(ATH11K_FW_DIR "/QCN9074/hw1.0/*"); +MODULE_FIRMWARE(ATH11K_FW_DIR "/WCN6855/hw2.0/*"); +MODULE_FIRMWARE(ATH11K_FW_DIR "/WCN6855/hw2.1/*"); diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 1ae7af02c364..1380811827a8 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -382,22 +382,23 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, return -ENOBUFS; } + mutex_lock(&ar->ab->tbl_mtx_lock); spin_lock_bh(&ar->ab->base_lock); peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr); if (peer) { if (peer->vdev_id == param->vdev_id) { spin_unlock_bh(&ar->ab->base_lock); + mutex_unlock(&ar->ab->tbl_mtx_lock); return -EINVAL; } /* Assume sta is transitioning to another band. * Remove here the peer from rhash. */ - mutex_lock(&ar->ab->tbl_mtx_lock); ath11k_peer_rhash_delete(ar->ab, peer); - mutex_unlock(&ar->ab->tbl_mtx_lock); } spin_unlock_bh(&ar->ab->base_lock); + mutex_unlock(&ar->ab->tbl_mtx_lock); ret = ath11k_wmi_send_peer_create_cmd(ar, param); if (ret) { diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h index 6dd17bafe3a0..9bd385d0a38c 100644 --- a/drivers/net/wireless/ath/ath11k/peer.h +++ b/drivers/net/wireless/ath/ath11k/peer.h @@ -35,6 +35,7 @@ struct ath11k_peer { u16 sec_type; u16 sec_type_grp; bool is_authorized; + bool dp_setup_done; }; void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id); diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 6fae4e61ede7..67443457f4da 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -613,13 +613,19 @@ ath11k_reg_build_regd(struct ath11k_base *ab, { struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL; struct cur_reg_rule *reg_rule; - u8 i = 0, j = 0; + u8 i = 0, j = 0, k = 0; u8 num_rules; u16 max_bw; u32 flags; char alpha2[3]; - num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules; + num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules; + + /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list. + * This can be updated after complete 6 GHz regulatory support is added. + */ + if (reg_info->is_ext_reg_event) + num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; if (!num_rules) goto ret; @@ -640,24 +646,24 @@ ath11k_reg_build_regd(struct ath11k_base *ab, tmp_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region); ath11k_dbg(ab, ATH11K_DBG_REG, - "\r\nCountry %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n", + "Country %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n", alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region), reg_info->dfs_region, num_rules); /* Update reg_rules[] below. Firmware is expected to - * send these rules in order(2G rules first and then 5G) + * send these rules in order(2 GHz rules first and then 5 GHz) */ for (; i < num_rules; i++) { - if (reg_info->num_2g_reg_rules && - (i < reg_info->num_2g_reg_rules)) { - reg_rule = reg_info->reg_rules_2g_ptr + i; + if (reg_info->num_2ghz_reg_rules && + (i < reg_info->num_2ghz_reg_rules)) { + reg_rule = reg_info->reg_rules_2ghz_ptr + i; max_bw = min_t(u16, reg_rule->max_bw, - reg_info->max_bw_2g); + reg_info->max_bw_2ghz); flags = 0; - } else if (reg_info->num_5g_reg_rules && - (j < reg_info->num_5g_reg_rules)) { - reg_rule = reg_info->reg_rules_5g_ptr + j++; + } else if (reg_info->num_5ghz_reg_rules && + (j < reg_info->num_5ghz_reg_rules)) { + reg_rule = reg_info->reg_rules_5ghz_ptr + j++; max_bw = min_t(u16, reg_rule->max_bw, - reg_info->max_bw_5g); + reg_info->max_bw_5ghz); /* FW doesn't pass NL80211_RRF_AUTO_BW flag for * BW Auto correction, we can enable this by default @@ -666,6 +672,14 @@ ath11k_reg_build_regd(struct ath11k_base *ab, * per other BW rule flags we pass from here */ flags = NL80211_RRF_AUTO_BW; + } else if (reg_info->is_ext_reg_event && + reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] && + (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) { + reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] + + k++; + max_bw = min_t(u16, reg_rule->max_bw, + reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]); + flags = NL80211_RRF_AUTO_BW; } else { break; } @@ -693,12 +707,21 @@ ath11k_reg_build_regd(struct ath11k_base *ab, continue; } - ath11k_dbg(ab, ATH11K_DBG_REG, - "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", - i + 1, reg_rule->start_freq, reg_rule->end_freq, - max_bw, reg_rule->ant_gain, reg_rule->reg_power, - tmp_regd->reg_rules[i].dfs_cac_ms, - flags); + if (reg_info->is_ext_reg_event) { + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d) (%d, %d)\n", + i + 1, reg_rule->start_freq, reg_rule->end_freq, + max_bw, reg_rule->ant_gain, reg_rule->reg_power, + tmp_regd->reg_rules[i].dfs_cac_ms, flags, + reg_rule->psd_flag, reg_rule->psd_eirp); + } else { + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", + i + 1, reg_rule->start_freq, reg_rule->end_freq, + max_bw, reg_rule->ant_gain, reg_rule->reg_power, + tmp_regd->reg_rules[i].dfs_cac_ms, + flags); + } } tmp_regd->n_reg_rules = i; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index b3a7d7bfe17c..d0b59bc2905a 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -82,6 +82,12 @@ struct wmi_tlv_fw_stats_parse { bool chain_rssi_done; }; +struct wmi_tlv_mgmt_rx_parse { + const struct wmi_mgmt_rx_hdr *fixed; + const u8 *frame_buf; + bool frame_buf_done; +}; + static const struct wmi_tlv_policy wmi_tlv_policies[] = { [WMI_TAG_ARRAY_BYTE] = { .min_len = 0 }, @@ -105,6 +111,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { = { .min_len = sizeof(struct wmi_vdev_stopped_event) }, [WMI_TAG_REG_CHAN_LIST_CC_EVENT] = { .min_len = sizeof(struct wmi_reg_chan_list_cc_event) }, + [WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT] + = { .min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) }, [WMI_TAG_MGMT_RX_HDR] = { .min_len = sizeof(struct wmi_mgmt_rx_hdr) }, [WMI_TAG_MGMT_TX_COMPL_EVENT] @@ -863,7 +871,8 @@ static void ath11k_wmi_put_wmi_channel(struct wmi_channel *chan, chan->band_center_freq2 = arg->channel.band_center_freq1; - } else if (arg->channel.mode == MODE_11AC_VHT80_80) { + } else if ((arg->channel.mode == MODE_11AC_VHT80_80) || + (arg->channel.mode == MODE_11AX_HE80_80)) { chan->band_center_freq2 = arg->channel.band_center_freq2; } else { chan->band_center_freq2 = 0; @@ -2068,6 +2077,12 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar, WMI_SCAN_EVENT_FOREIGN_CHAN | WMI_SCAN_EVENT_DEQUEUED; arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; + + if (test_bit(WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE, + ar->ab->wmi_ab.svc_map)) + arg->scan_ctrl_flags_ext |= + WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE; + arg->num_bssid = 1; /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be @@ -2149,6 +2164,8 @@ ath11k_wmi_copy_scan_event_cntrl_flags(struct wmi_start_scan_cmd *cmd, /* for adaptive scan mode using 3 bits (21 - 23 bits) */ WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags, param->adaptive_dwell_time_mode); + + cmd->scan_ctrl_flags_ext = param->scan_ctrl_flags_ext; } int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, @@ -3966,6 +3983,10 @@ ath11k_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg, wmi_cfg->sched_params = tg_cfg->sched_params; wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count; wmi_cfg->twt_ap_sta_count = tg_cfg->twt_ap_sta_count; + wmi_cfg->host_service_flags &= + ~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT); + wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported << + WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT); } static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, @@ -4184,6 +4205,10 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) ab->hw_params.hw_ops->wmi_init_config(ab, &config); + if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, + ab->wmi_ab.svc_map)) + config.is_reg_cc_ext_event_supported = 1; + memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config)); init_param.res_cfg = &wmi_sc->wlan_resource_config; @@ -4907,6 +4932,26 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf return 0; } +static void ath11k_print_reg_rule(struct ath11k_base *ab, const char *band, + u32 num_reg_rules, + struct cur_reg_rule *reg_rule_ptr) +{ + struct cur_reg_rule *reg_rule = reg_rule_ptr; + u32 count; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "number of reg rules in %s band: %d\n", + band, num_reg_rules); + + for (count = 0; count < num_reg_rules; count++) { + ath11k_dbg(ab, ATH11K_DBG_WMI, + "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d)\n", + count + 1, reg_rule->start_freq, reg_rule->end_freq, + reg_rule->max_bw, reg_rule->ant_gain, + reg_rule->reg_power, reg_rule->flags); + reg_rule++; + } +} + static struct cur_reg_rule *create_reg_rules_from_wmi(u32 num_reg_rules, struct wmi_regulatory_rule_struct *wmi_reg_rule) @@ -4951,7 +4996,7 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, const void **tb; const struct wmi_reg_chan_list_cc_event *chan_list_event_hdr; struct wmi_regulatory_rule_struct *wmi_reg_rule; - u32 num_2g_reg_rules, num_5g_reg_rules; + u32 num_2ghz_reg_rules, num_5ghz_reg_rules; int ret; ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n"); @@ -4970,10 +5015,10 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, return -EPROTO; } - reg_info->num_2g_reg_rules = chan_list_event_hdr->num_2g_reg_rules; - reg_info->num_5g_reg_rules = chan_list_event_hdr->num_5g_reg_rules; + reg_info->num_2ghz_reg_rules = chan_list_event_hdr->num_2ghz_reg_rules; + reg_info->num_5ghz_reg_rules = chan_list_event_hdr->num_5ghz_reg_rules; - if (!(reg_info->num_2g_reg_rules + reg_info->num_5g_reg_rules)) { + if (!(reg_info->num_2ghz_reg_rules + reg_info->num_5ghz_reg_rules)) { ath11k_warn(ab, "No regulatory rules available in the event info\n"); kfree(tb); return -EINVAL; @@ -4987,61 +5032,68 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, reg_info->phy_id = chan_list_event_hdr->phy_id; reg_info->ctry_code = chan_list_event_hdr->country_id; reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code; - if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_PASS) - reg_info->status_code = REG_SET_CC_STATUS_PASS; - else if (chan_list_event_hdr->status_code == WMI_REG_CURRENT_ALPHA2_NOT_FOUND) - reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND; - else if (chan_list_event_hdr->status_code == WMI_REG_INIT_ALPHA2_NOT_FOUND) - reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND; - else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_CHANGE_NOT_ALLOWED) - reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED; - else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_NO_MEMORY) - reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY; - else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL) - reg_info->status_code = REG_SET_CC_STATUS_FAIL; - - reg_info->min_bw_2g = chan_list_event_hdr->min_bw_2g; - reg_info->max_bw_2g = chan_list_event_hdr->max_bw_2g; - reg_info->min_bw_5g = chan_list_event_hdr->min_bw_5g; - reg_info->max_bw_5g = chan_list_event_hdr->max_bw_5g; - - num_2g_reg_rules = reg_info->num_2g_reg_rules; - num_5g_reg_rules = reg_info->num_5g_reg_rules; ath11k_dbg(ab, ATH11K_DBG_WMI, - "%s:cc %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d", - __func__, reg_info->alpha2, reg_info->dfs_region, - reg_info->min_bw_2g, reg_info->max_bw_2g, - reg_info->min_bw_5g, reg_info->max_bw_5g); + "status_code %s", + ath11k_cc_status_to_str(reg_info->status_code)); + + reg_info->status_code = + ath11k_wmi_cc_setting_code_to_reg(chan_list_event_hdr->status_code); + + reg_info->is_ext_reg_event = false; + + reg_info->min_bw_2ghz = chan_list_event_hdr->min_bw_2ghz; + reg_info->max_bw_2ghz = chan_list_event_hdr->max_bw_2ghz; + reg_info->min_bw_5ghz = chan_list_event_hdr->min_bw_5ghz; + reg_info->max_bw_5ghz = chan_list_event_hdr->max_bw_5ghz; + + num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules; + num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", + reg_info->alpha2, reg_info->dfs_region, + reg_info->min_bw_2ghz, reg_info->max_bw_2ghz, + reg_info->min_bw_5ghz, reg_info->max_bw_5ghz); ath11k_dbg(ab, ATH11K_DBG_WMI, - "%s: num_2g_reg_rules %d num_5g_reg_rules %d", __func__, - num_2g_reg_rules, num_5g_reg_rules); + "num_2ghz_reg_rules %d num_5ghz_reg_rules %d", + num_2ghz_reg_rules, num_5ghz_reg_rules); wmi_reg_rule = (struct wmi_regulatory_rule_struct *)((u8 *)chan_list_event_hdr + sizeof(*chan_list_event_hdr) + sizeof(struct wmi_tlv)); - if (num_2g_reg_rules) { - reg_info->reg_rules_2g_ptr = create_reg_rules_from_wmi(num_2g_reg_rules, - wmi_reg_rule); - if (!reg_info->reg_rules_2g_ptr) { + if (num_2ghz_reg_rules) { + reg_info->reg_rules_2ghz_ptr = + create_reg_rules_from_wmi(num_2ghz_reg_rules, + wmi_reg_rule); + if (!reg_info->reg_rules_2ghz_ptr) { kfree(tb); - ath11k_warn(ab, "Unable to Allocate memory for 2g rules\n"); + ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n"); return -ENOMEM; } + + ath11k_print_reg_rule(ab, "2 GHz", + num_2ghz_reg_rules, + reg_info->reg_rules_2ghz_ptr); } - if (num_5g_reg_rules) { - wmi_reg_rule += num_2g_reg_rules; - reg_info->reg_rules_5g_ptr = create_reg_rules_from_wmi(num_5g_reg_rules, - wmi_reg_rule); - if (!reg_info->reg_rules_5g_ptr) { + if (num_5ghz_reg_rules) { + wmi_reg_rule += num_2ghz_reg_rules; + reg_info->reg_rules_5ghz_ptr = + create_reg_rules_from_wmi(num_5ghz_reg_rules, + wmi_reg_rule); + if (!reg_info->reg_rules_5ghz_ptr) { kfree(tb); - ath11k_warn(ab, "Unable to Allocate memory for 5g rules\n"); + ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n"); return -ENOMEM; } + + ath11k_print_reg_rule(ab, "5 GHz", + num_5ghz_reg_rules, + reg_info->reg_rules_5ghz_ptr); } ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory channel list\n"); @@ -5050,6 +5102,429 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, return 0; } +static struct cur_reg_rule +*create_ext_reg_rules_from_wmi(u32 num_reg_rules, + struct wmi_regulatory_ext_rule *wmi_reg_rule) +{ + struct cur_reg_rule *reg_rule_ptr; + u32 count; + + reg_rule_ptr = kcalloc(num_reg_rules, sizeof(*reg_rule_ptr), GFP_ATOMIC); + + if (!reg_rule_ptr) + return NULL; + + for (count = 0; count < num_reg_rules; count++) { + reg_rule_ptr[count].start_freq = + u32_get_bits(wmi_reg_rule[count].freq_info, + REG_RULE_START_FREQ); + reg_rule_ptr[count].end_freq = + u32_get_bits(wmi_reg_rule[count].freq_info, + REG_RULE_END_FREQ); + reg_rule_ptr[count].max_bw = + u32_get_bits(wmi_reg_rule[count].bw_pwr_info, + REG_RULE_MAX_BW); + reg_rule_ptr[count].reg_power = + u32_get_bits(wmi_reg_rule[count].bw_pwr_info, + REG_RULE_REG_PWR); + reg_rule_ptr[count].ant_gain = + u32_get_bits(wmi_reg_rule[count].bw_pwr_info, + REG_RULE_ANT_GAIN); + reg_rule_ptr[count].flags = + u32_get_bits(wmi_reg_rule[count].flag_info, + REG_RULE_FLAGS); + reg_rule_ptr[count].psd_flag = + u32_get_bits(wmi_reg_rule[count].psd_power_info, + REG_RULE_PSD_INFO); + reg_rule_ptr[count].psd_eirp = + u32_get_bits(wmi_reg_rule[count].psd_power_info, + REG_RULE_PSD_EIRP); + } + + return reg_rule_ptr; +} + +static u8 +ath11k_invalid_5ghz_reg_ext_rules_from_wmi(u32 num_reg_rules, + const struct wmi_regulatory_ext_rule *rule) +{ + u8 num_invalid_5ghz_rules = 0; + u32 count, start_freq; + + for (count = 0; count < num_reg_rules; count++) { + start_freq = u32_get_bits(rule[count].freq_info, + REG_RULE_START_FREQ); + + if (start_freq >= ATH11K_MIN_6G_FREQ) + num_invalid_5ghz_rules++; + } + + return num_invalid_5ghz_rules; +} + +static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, + struct sk_buff *skb, + struct cur_regulatory_info *reg_info) +{ + const void **tb; + const struct wmi_reg_chan_list_cc_ext_event *ev; + struct wmi_regulatory_ext_rule *ext_wmi_reg_rule; + u32 num_2ghz_reg_rules, num_5ghz_reg_rules; + u32 num_6ghz_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 num_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 total_reg_rules = 0; + int ret, i, j, num_invalid_5ghz_ext_rules = 0; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n"); + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]; + if (!ev) { + ath11k_warn(ab, "failed to fetch reg chan list ext update ev\n"); + kfree(tb); + return -EPROTO; + } + + reg_info->num_2ghz_reg_rules = ev->num_2ghz_reg_rules; + reg_info->num_5ghz_reg_rules = ev->num_5ghz_reg_rules; + reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] = + ev->num_6ghz_reg_rules_ap_lpi; + reg_info->num_6ghz_rules_ap[WMI_REG_STANDARD_POWER_AP] = + ev->num_6ghz_reg_rules_ap_sp; + reg_info->num_6ghz_rules_ap[WMI_REG_VERY_LOW_POWER_AP] = + ev->num_6ghz_reg_rules_ap_vlp; + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i] = + ev->num_6ghz_reg_rules_client_lpi[i]; + reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i] = + ev->num_6ghz_reg_rules_client_sp[i]; + reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ev->num_6ghz_reg_rules_client_vlp[i]; + } + + num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules; + num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules; + + total_reg_rules += num_2ghz_reg_rules; + total_reg_rules += num_5ghz_reg_rules; + + if ((num_2ghz_reg_rules > MAX_REG_RULES) || + (num_5ghz_reg_rules > MAX_REG_RULES)) { + ath11k_warn(ab, "Num reg rules for 2.4 GHz/5 GHz exceeds max limit (num_2ghz_reg_rules: %d num_5ghz_reg_rules: %d max_rules: %d)\n", + num_2ghz_reg_rules, num_5ghz_reg_rules, MAX_REG_RULES); + kfree(tb); + return -EINVAL; + } + + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { + num_6ghz_reg_rules_ap[i] = reg_info->num_6ghz_rules_ap[i]; + + if (num_6ghz_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) { + ath11k_warn(ab, "Num 6 GHz reg rules for AP mode(%d) exceeds max limit (num_6ghz_reg_rules_ap: %d, max_rules: %d)\n", + i, num_6ghz_reg_rules_ap[i], MAX_6GHZ_REG_RULES); + kfree(tb); + return -EINVAL; + } + + total_reg_rules += num_6ghz_reg_rules_ap[i]; + } + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + num_6ghz_client[WMI_REG_INDOOR_AP][i] = + reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i]; + total_reg_rules += num_6ghz_client[WMI_REG_INDOOR_AP][i]; + + num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i]; + total_reg_rules += num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i]; + + num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i]; + total_reg_rules += num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i]; + + if ((num_6ghz_client[WMI_REG_INDOOR_AP][i] > MAX_6GHZ_REG_RULES) || + (num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] > + MAX_6GHZ_REG_RULES) || + (num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] > + MAX_6GHZ_REG_RULES)) { + ath11k_warn(ab, + "Num 6 GHz client reg rules exceeds max limit, for client(type: %d)\n", + i); + kfree(tb); + return -EINVAL; + } + } + + if (!total_reg_rules) { + ath11k_warn(ab, "No reg rules available\n"); + kfree(tb); + return -EINVAL; + } + + memcpy(reg_info->alpha2, &ev->alpha2, REG_ALPHA2_LEN); + + reg_info->dfs_region = ev->dfs_region; + reg_info->phybitmap = ev->phybitmap; + reg_info->num_phy = ev->num_phy; + reg_info->phy_id = ev->phy_id; + reg_info->ctry_code = ev->country_id; + reg_info->reg_dmn_pair = ev->domain_code; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "status_code %s", + ath11k_cc_status_to_str(reg_info->status_code)); + + reg_info->status_code = + ath11k_wmi_cc_setting_code_to_reg(ev->status_code); + + reg_info->is_ext_reg_event = true; + + reg_info->min_bw_2ghz = ev->min_bw_2ghz; + reg_info->max_bw_2ghz = ev->max_bw_2ghz; + reg_info->min_bw_5ghz = ev->min_bw_5ghz; + reg_info->max_bw_5ghz = ev->max_bw_5ghz; + + reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP] = + ev->min_bw_6ghz_ap_lpi; + reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP] = + ev->max_bw_6ghz_ap_lpi; + reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = + ev->min_bw_6ghz_ap_sp; + reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = + ev->max_bw_6ghz_ap_sp; + reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = + ev->min_bw_6ghz_ap_vlp; + reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = + ev->max_bw_6ghz_ap_vlp; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz AP BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n", + reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP], + reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP], + reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP], + reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP], + reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP], + reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP]); + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i] = + ev->min_bw_6ghz_client_lpi[i]; + reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i] = + ev->max_bw_6ghz_client_lpi[i]; + reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + ev->min_bw_6ghz_client_sp[i]; + reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + ev->max_bw_6ghz_client_sp[i]; + reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ev->min_bw_6ghz_client_vlp[i]; + reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ev->max_bw_6ghz_client_vlp[i]; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz %s BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n", + ath11k_6ghz_client_type_to_str(i), + reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i], + reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i], + reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i], + reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i], + reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i], + reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i]); + } + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", + reg_info->alpha2, reg_info->dfs_region, + reg_info->min_bw_2ghz, reg_info->max_bw_2ghz, + reg_info->min_bw_5ghz, reg_info->max_bw_5ghz); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "num_2ghz_reg_rules %d num_5ghz_reg_rules %d", + num_2ghz_reg_rules, num_5ghz_reg_rules); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "num_6ghz_reg_rules_ap_lpi: %d num_6ghz_reg_rules_ap_sp: %d num_6ghz_reg_rules_ap_vlp: %d", + num_6ghz_reg_rules_ap[WMI_REG_INDOOR_AP], + num_6ghz_reg_rules_ap[WMI_REG_STANDARD_POWER_AP], + num_6ghz_reg_rules_ap[WMI_REG_VERY_LOW_POWER_AP]); + + j = WMI_REG_DEFAULT_CLIENT; + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz Regular client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d", + num_6ghz_client[WMI_REG_INDOOR_AP][j], + num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j], + num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]); + + j = WMI_REG_SUBORDINATE_CLIENT; + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz Subordinate client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d", + num_6ghz_client[WMI_REG_INDOOR_AP][j], + num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j], + num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]); + + ext_wmi_reg_rule = + (struct wmi_regulatory_ext_rule *)((u8 *)ev + sizeof(*ev) + + sizeof(struct wmi_tlv)); + if (num_2ghz_reg_rules) { + reg_info->reg_rules_2ghz_ptr = + create_ext_reg_rules_from_wmi(num_2ghz_reg_rules, + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_2ghz_ptr) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n"); + return -ENOMEM; + } + + ath11k_print_reg_rule(ab, "2 GHz", + num_2ghz_reg_rules, + reg_info->reg_rules_2ghz_ptr); + } + + ext_wmi_reg_rule += num_2ghz_reg_rules; + + /* Firmware might include 6 GHz reg rule in 5 GHz rule list + * for few countries along with separate 6 GHz rule. + * Having same 6 GHz reg rule in 5 GHz and 6 GHz rules list + * causes intersect check to be true, and same rules will be + * shown multiple times in iw cmd. + * Hence, avoid parsing 6 GHz rule from 5 GHz reg rule list + */ + num_invalid_5ghz_ext_rules = + ath11k_invalid_5ghz_reg_ext_rules_from_wmi(num_5ghz_reg_rules, + ext_wmi_reg_rule); + + if (num_invalid_5ghz_ext_rules) { + ath11k_dbg(ab, ATH11K_DBG_WMI, + "CC: %s 5 GHz reg rules number %d from fw, %d number of invalid 5 GHz rules", + reg_info->alpha2, reg_info->num_5ghz_reg_rules, + num_invalid_5ghz_ext_rules); + + num_5ghz_reg_rules = num_5ghz_reg_rules - num_invalid_5ghz_ext_rules; + reg_info->num_5ghz_reg_rules = num_5ghz_reg_rules; + } + + if (num_5ghz_reg_rules) { + reg_info->reg_rules_5ghz_ptr = + create_ext_reg_rules_from_wmi(num_5ghz_reg_rules, + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_5ghz_ptr) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n"); + return -ENOMEM; + } + + ath11k_print_reg_rule(ab, "5 GHz", + num_5ghz_reg_rules, + reg_info->reg_rules_5ghz_ptr); + } + + /* We have adjusted the number of 5 GHz reg rules above. But still those + * many rules needs to be adjusted in ext_wmi_reg_rule. + * + * NOTE: num_invalid_5ghz_ext_rules will be 0 for rest other cases. + */ + ext_wmi_reg_rule += (num_5ghz_reg_rules + num_invalid_5ghz_ext_rules); + + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { + reg_info->reg_rules_6ghz_ap_ptr[i] = + create_ext_reg_rules_from_wmi(num_6ghz_reg_rules_ap[i], + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_6ghz_ap_ptr[i]) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 6 GHz AP rules\n"); + return -ENOMEM; + } + + ath11k_print_reg_rule(ab, ath11k_6ghz_ap_type_to_str(i), + num_6ghz_reg_rules_ap[i], + reg_info->reg_rules_6ghz_ap_ptr[i]); + + ext_wmi_reg_rule += num_6ghz_reg_rules_ap[i]; + } + + for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) { + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz AP type %s", ath11k_6ghz_ap_type_to_str(j)); + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->reg_rules_6ghz_client_ptr[j][i] = + create_ext_reg_rules_from_wmi(num_6ghz_client[j][i], + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_6ghz_client_ptr[j][i]) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 6 GHz client rules\n"); + return -ENOMEM; + } + + ath11k_print_reg_rule(ab, + ath11k_6ghz_client_type_to_str(i), + num_6ghz_client[j][i], + reg_info->reg_rules_6ghz_client_ptr[j][i]); + + ext_wmi_reg_rule += num_6ghz_client[j][i]; + } + } + + reg_info->client_type = ev->client_type; + reg_info->rnr_tpe_usable = ev->rnr_tpe_usable; + reg_info->unspecified_ap_usable = + ev->unspecified_ap_usable; + reg_info->domain_code_6ghz_ap[WMI_REG_INDOOR_AP] = + ev->domain_code_6ghz_ap_lpi; + reg_info->domain_code_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = + ev->domain_code_6ghz_ap_sp; + reg_info->domain_code_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = + ev->domain_code_6ghz_ap_vlp; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s, sp %s, vlp %s\n", + ath11k_6ghz_client_type_to_str(reg_info->client_type), + reg_info->rnr_tpe_usable, + reg_info->unspecified_ap_usable, + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_lpi), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_sp), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_vlp)); + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->domain_code_6ghz_client[WMI_REG_INDOOR_AP][i] = + ev->domain_code_6ghz_client_lpi[i]; + reg_info->domain_code_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + ev->domain_code_6ghz_client_sp[i]; + reg_info->domain_code_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ev->domain_code_6ghz_client_vlp[i]; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz client type %s client sub domain: lpi %s, sp %s, vlp %s\n", + ath11k_6ghz_client_type_to_str(i), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_lpi[i]), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_sp[i]), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_vlp[i]) + ); + } + + reg_info->domain_code_6ghz_super_id = ev->domain_code_6ghz_super_id; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz client_type %s 6 GHz super domain %s", + ath11k_6ghz_client_type_to_str(reg_info->client_type), + ath11k_super_reg_6ghz_to_str(reg_info->domain_code_6ghz_super_id)); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory ext channel list\n"); + + kfree(tb); + return 0; +} + static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *skb, struct wmi_peer_delete_resp_event *peer_del_resp) { @@ -5165,28 +5640,49 @@ static int ath11k_pull_vdev_stopped_param_tlv(struct ath11k_base *ab, struct sk_ return 0; } +static int ath11k_wmi_tlv_mgmt_rx_parse(struct ath11k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_mgmt_rx_parse *parse = data; + + switch (tag) { + case WMI_TAG_MGMT_RX_HDR: + parse->fixed = ptr; + break; + case WMI_TAG_ARRAY_BYTE: + if (!parse->frame_buf_done) { + parse->frame_buf = ptr; + parse->frame_buf_done = true; + } + break; + } + return 0; +} + static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab, struct sk_buff *skb, struct mgmt_rx_event_params *hdr) { - const void **tb; + struct wmi_tlv_mgmt_rx_parse parse = { }; const struct wmi_mgmt_rx_hdr *ev; const u8 *frame; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); - if (IS_ERR(tb)) { - ret = PTR_ERR(tb); - ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_tlv_mgmt_rx_parse, + &parse); + if (ret) { + ath11k_warn(ab, "failed to parse mgmt rx tlv %d\n", + ret); return ret; } - ev = tb[WMI_TAG_MGMT_RX_HDR]; - frame = tb[WMI_TAG_ARRAY_BYTE]; + ev = parse.fixed; + frame = parse.frame_buf; if (!ev || !frame) { ath11k_warn(ab, "failed to fetch mgmt rx hdr"); - kfree(tb); return -EPROTO; } @@ -5205,7 +5701,6 @@ static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab, if (skb->len < (frame - skb->data) + hdr->buf_len) { ath11k_warn(ab, "invalid length in mgmt rx hdr ev"); - kfree(tb); return -EPROTO; } @@ -5217,12 +5712,11 @@ static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab, ath11k_ce_byte_swap(skb->data, hdr->buf_len); - kfree(tb); return 0; } -static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, - u32 status) +static int wmi_process_mgmt_tx_comp(struct ath11k *ar, + struct wmi_mgmt_tx_compl_event *tx_compl_param) { struct sk_buff *msdu; struct ieee80211_tx_info *info; @@ -5230,24 +5724,29 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, int num_mgmt; spin_lock_bh(&ar->txmgmt_idr_lock); - msdu = idr_find(&ar->txmgmt_idr, desc_id); + msdu = idr_find(&ar->txmgmt_idr, tx_compl_param->desc_id); if (!msdu) { ath11k_warn(ar->ab, "received mgmt tx compl for invalid msdu_id: %d\n", - desc_id); + tx_compl_param->desc_id); spin_unlock_bh(&ar->txmgmt_idr_lock); return -ENOENT; } - idr_remove(&ar->txmgmt_idr, desc_id); + idr_remove(&ar->txmgmt_idr, tx_compl_param->desc_id); spin_unlock_bh(&ar->txmgmt_idr_lock); skb_cb = ATH11K_SKB_CB(msdu); dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); info = IEEE80211_SKB_CB(msdu); - if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) + if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && + !tx_compl_param->status) { info->flags |= IEEE80211_TX_STAT_ACK; + if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI, + ar->ab->wmi_ab.svc_map)) + info->status.ack_signal = tx_compl_param->ack_rssi; + } ieee80211_tx_status_irqsafe(ar->hw, msdu); @@ -5259,7 +5758,7 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi mgmt tx comp pending %d desc id %d\n", - num_mgmt, desc_id); + num_mgmt, tx_compl_param->desc_id); if (!num_mgmt) wake_up(&ar->txmgmt_empty_waitq); @@ -5292,6 +5791,7 @@ static int ath11k_pull_mgmt_tx_compl_param_tlv(struct ath11k_base *ab, param->pdev_id = ev->pdev_id; param->desc_id = ev->desc_id; param->status = ev->status; + param->ack_rssi = ev->ack_rssi; kfree(tb); return 0; @@ -6491,12 +6991,14 @@ static bool ath11k_reg_is_world_alpha(char *alpha) return false; } -static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb) +static int ath11k_reg_chan_list_event(struct ath11k_base *ab, + struct sk_buff *skb, + enum wmi_reg_chan_list_cmd_type id) { struct cur_regulatory_info *reg_info = NULL; struct ieee80211_regdomain *regd = NULL; bool intersect = false; - int ret = 0, pdev_idx; + int ret = 0, pdev_idx, i, j; struct ath11k *ar; reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC); @@ -6505,7 +7007,11 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk goto fallback; } - ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info); + if (id == WMI_REG_CHAN_LIST_CC_ID) + ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info); + else + ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info); + if (ret) { ath11k_warn(ab, "failed to extract regulatory info from received event\n"); goto fallback; @@ -6605,8 +7111,16 @@ fallback: WARN_ON(1); mem_free: if (reg_info) { - kfree(reg_info->reg_rules_2g_ptr); - kfree(reg_info->reg_rules_5g_ptr); + kfree(reg_info->reg_rules_2ghz_ptr); + kfree(reg_info->reg_rules_5ghz_ptr); + if (reg_info->is_ext_reg_event) { + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) + kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); + + for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) + kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]); + } kfree(reg_info); } return ret; @@ -7062,13 +7576,12 @@ static void ath11k_mgmt_tx_compl_event(struct ath11k_base *ab, struct sk_buff *s goto exit; } - wmi_process_mgmt_tx_comp(ar, tx_compl_param.desc_id, - tx_compl_param.status); + wmi_process_mgmt_tx_comp(ar, &tx_compl_param); ath11k_dbg(ab, ATH11K_DBG_MGMT, - "mgmt tx compl ev pdev_id %d, desc_id %d, status %d", + "mgmt tx compl ev pdev_id %d, desc_id %d, status %d ack_rssi %d", tx_compl_param.pdev_id, tx_compl_param.desc_id, - tx_compl_param.status); + tx_compl_param.status, tx_compl_param.ack_rssi); exit: rcu_read_unlock(); @@ -8039,7 +8552,10 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) ath11k_service_ready_ext2_event(ab, skb); break; case WMI_REG_CHAN_LIST_CC_EVENTID: - ath11k_reg_chan_list_event(ab, skb); + ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_ID); + break; + case WMI_REG_CHAN_LIST_CC_EXT_EVENTID: + ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_EXT_ID); break; case WMI_READY_EVENTID: ath11k_ready_event(ab, skb); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 0a045af5419b..92fddb77669c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -797,6 +797,7 @@ enum wmi_tlv_event_id { WMI_RMC_NEW_LEADER_EVENTID = WMI_TLV_CMD(WMI_GRP_RMC), WMI_REG_CHAN_LIST_CC_EVENTID = WMI_TLV_CMD(WMI_GRP_REGULATORY), WMI_11D_NEW_COUNTRY_EVENTID, + WMI_REG_CHAN_LIST_CC_EXT_EVENTID, WMI_NDI_CAP_RSP_EVENTID = WMI_TLV_CMD(WMI_GRP_PROTOTYPE), WMI_NDP_INITIATOR_RSP_EVENTID, WMI_NDP_RESPONDER_RSP_EVENTID, @@ -1865,6 +1866,8 @@ enum wmi_tlv_tag { WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD, WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD, WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD, + WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9, + WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT, WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8, WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD, WMI_TAG_MAX @@ -2093,10 +2096,14 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_EXT2_MSG = 220, WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT = 246, WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249, + WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263, /* The second 128 bits */ WMI_MAX_EXT_SERVICE = 256, + WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL = 265, + WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281, WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326, + WMI_TLV_SERVICE_SUPPORT_11D_FOR_HOST_SCAN = 357, /* The third 128 bits */ WMI_MAX_EXT2_SERVICE = 384 @@ -2310,6 +2317,9 @@ struct wmi_init_cmd { } __packed; #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) +#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18) + +#define WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT 4 struct wmi_resource_config { u32 tlv_header; @@ -2370,6 +2380,15 @@ struct wmi_resource_config { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; + u32 max_nlo_ssids; + u32 num_pkt_filters; + u32 num_max_sta_vdevs; + u32 max_bssid_indicator; + u32 ul_resp_config; + u32 msdu_flow_override_config0; + u32 msdu_flow_override_config1; + u32 flags2; + u32 host_service_flags; } __packed; struct wmi_service_ready_event { @@ -2852,36 +2871,40 @@ struct rx_reorder_queue_remove_params { #define REG_RULE_MAX_BW 0x0000ffff #define REG_RULE_REG_PWR 0x00ff0000 #define REG_RULE_ANT_GAIN 0xff000000 +#define REG_RULE_PSD_INFO BIT(0) +#define REG_RULE_PSD_EIRP 0xff0000 #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) -#define HECAP_PHYDWORD_0 0 -#define HECAP_PHYDWORD_1 1 -#define HECAP_PHYDWORD_2 2 +#define HE_PHYCAP_BYTE_0 0 +#define HE_PHYCAP_BYTE_1 1 +#define HE_PHYCAP_BYTE_2 2 +#define HE_PHYCAP_BYTE_3 3 +#define HE_PHYCAP_BYTE_4 4 -#define HECAP_PHY_SU_BFER BIT(31) +#define HECAP_PHY_SU_BFER BIT(7) #define HECAP_PHY_SU_BFEE BIT(0) #define HECAP_PHY_MU_BFER BIT(1) -#define HECAP_PHY_UL_MUMIMO BIT(22) -#define HECAP_PHY_UL_MUOFDMA BIT(23) +#define HECAP_PHY_UL_MUMIMO BIT(6) +#define HECAP_PHY_UL_MUOFDMA BIT(7) #define HECAP_PHY_SUBFMR_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HECAP_PHYDWORD_0]) + FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HE_PHYCAP_BYTE_3]) #define HECAP_PHY_SUBFME_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HECAP_PHYDWORD_1]) + FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HE_PHYCAP_BYTE_4]) #define HECAP_PHY_MUBFMR_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HECAP_PHYDWORD_1]) + FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HE_PHYCAP_BYTE_4]) #define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HECAP_PHYDWORD_0]) + FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HE_PHYCAP_BYTE_2]) #define HECAP_PHY_ULOFDMA_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HECAP_PHYDWORD_0]) + FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HE_PHYCAP_BYTE_2]) #define HE_MODE_SU_TX_BFEE BIT(0) #define HE_MODE_SU_TX_BFER BIT(1) @@ -2894,8 +2917,11 @@ struct rx_reorder_queue_remove_params { #define HE_DL_MUOFDMA_ENABLE 1 #define HE_UL_MUOFDMA_ENABLE 1 #define HE_DL_MUMIMO_ENABLE 1 +#define HE_UL_MUMIMO_ENABLE 1 #define HE_MU_BFEE_ENABLE 1 #define HE_SU_BFEE_ENABLE 1 +#define HE_MU_BFER_ENABLE 1 +#define HE_SU_BFER_ENABLE 1 #define HE_VHT_SOUNDING_MODE_ENABLE 1 #define HE_SU_MU_SOUNDING_MODE_ENABLE 1 @@ -3223,6 +3249,10 @@ struct wmi_start_scan_cmd { #define WMI_SCAN_DWELL_MODE_MASK 0x00E00000 #define WMI_SCAN_DWELL_MODE_SHIFT 21 +#define WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE 0x00000800 + +#define WMI_SCAN_CONFIG_PER_CHANNEL_MASK GENMASK(19, 0) +#define WMI_SCAN_CH_FLAG_SCAN_ONLY_IF_RNR_FOUND BIT(20) enum { WMI_SCAN_DWELL_MODE_DEFAULT = 0, @@ -3270,6 +3300,7 @@ struct scan_req_params { }; u32 scan_events; }; + u32 scan_ctrl_flags_ext; u32 dwell_time_active; u32 dwell_time_active_2g; u32 dwell_time_passive; @@ -4040,6 +4071,7 @@ struct wmi_he_rate_set { #define MAX_REG_RULES 10 #define REG_ALPHA2_LEN 2 +#define MAX_6GHZ_REG_RULES 5 enum wmi_start_event_param { WMI_VDEV_START_RESP_EVENT = 0, @@ -4070,16 +4102,6 @@ enum wmi_vdev_start_resp_status_code { WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN = 4, }; -; -enum cc_setting_code { - REG_SET_CC_STATUS_PASS = 0, - REG_CURRENT_ALPHA2_NOT_FOUND = 1, - REG_INIT_ALPHA2_NOT_FOUND = 2, - REG_SET_CC_CHANGE_NOT_ALLOWED = 3, - REG_SET_CC_STATUS_NO_MEMORY = 4, - REG_SET_CC_STATUS_FAIL = 5, -}; - /* Regaulatory Rule Flags Passed by FW */ #define REGULATORY_CHAN_DISABLED BIT(0) #define REGULATORY_CHAN_NO_IR BIT(1) @@ -4093,15 +4115,216 @@ enum cc_setting_code { #define REGULATORY_CHAN_NO_20MHZ BIT(11) #define REGULATORY_CHAN_NO_10MHZ BIT(12) -enum { +enum wmi_reg_chan_list_cmd_type { + WMI_REG_CHAN_LIST_CC_ID = 0, + WMI_REG_CHAN_LIST_CC_EXT_ID = 1, +}; + +enum wmi_reg_cc_setting_code { WMI_REG_SET_CC_STATUS_PASS = 0, WMI_REG_CURRENT_ALPHA2_NOT_FOUND = 1, WMI_REG_INIT_ALPHA2_NOT_FOUND = 2, WMI_REG_SET_CC_CHANGE_NOT_ALLOWED = 3, WMI_REG_SET_CC_STATUS_NO_MEMORY = 4, WMI_REG_SET_CC_STATUS_FAIL = 5, + + /* add new setting code above, update in + * @enum cc_setting_code as well. + * Also handle it in ath11k_wmi_cc_setting_code_to_reg() + */ +}; + +enum cc_setting_code { + REG_SET_CC_STATUS_PASS = 0, + REG_CURRENT_ALPHA2_NOT_FOUND = 1, + REG_INIT_ALPHA2_NOT_FOUND = 2, + REG_SET_CC_CHANGE_NOT_ALLOWED = 3, + REG_SET_CC_STATUS_NO_MEMORY = 4, + REG_SET_CC_STATUS_FAIL = 5, + + /* add new setting code above, update in + * @enum wmi_reg_cc_setting_code as well. + * Also handle it in ath11k_cc_status_to_str() + */ +}; + +static inline enum cc_setting_code +ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code) +{ + switch (status_code) { + case WMI_REG_SET_CC_STATUS_PASS: + return REG_SET_CC_STATUS_PASS; + case WMI_REG_CURRENT_ALPHA2_NOT_FOUND: + return REG_CURRENT_ALPHA2_NOT_FOUND; + case WMI_REG_INIT_ALPHA2_NOT_FOUND: + return REG_INIT_ALPHA2_NOT_FOUND; + case WMI_REG_SET_CC_CHANGE_NOT_ALLOWED: + return REG_SET_CC_CHANGE_NOT_ALLOWED; + case WMI_REG_SET_CC_STATUS_NO_MEMORY: + return REG_SET_CC_STATUS_NO_MEMORY; + case WMI_REG_SET_CC_STATUS_FAIL: + return REG_SET_CC_STATUS_FAIL; + } + + return REG_SET_CC_STATUS_FAIL; +} + +static inline const char *ath11k_cc_status_to_str(enum cc_setting_code code) +{ + switch (code) { + case REG_SET_CC_STATUS_PASS: + return "REG_SET_CC_STATUS_PASS"; + case REG_CURRENT_ALPHA2_NOT_FOUND: + return "REG_CURRENT_ALPHA2_NOT_FOUND"; + case REG_INIT_ALPHA2_NOT_FOUND: + return "REG_INIT_ALPHA2_NOT_FOUND"; + case REG_SET_CC_CHANGE_NOT_ALLOWED: + return "REG_SET_CC_CHANGE_NOT_ALLOWED"; + case REG_SET_CC_STATUS_NO_MEMORY: + return "REG_SET_CC_STATUS_NO_MEMORY"; + case REG_SET_CC_STATUS_FAIL: + return "REG_SET_CC_STATUS_FAIL"; + } + + return "Unknown CC status"; +} + +enum wmi_reg_6ghz_ap_type { + WMI_REG_INDOOR_AP = 0, + WMI_REG_STANDARD_POWER_AP = 1, + WMI_REG_VERY_LOW_POWER_AP = 2, + + /* add AP type above, handle in ath11k_6ghz_ap_type_to_str() + */ + WMI_REG_CURRENT_MAX_AP_TYPE, + WMI_REG_MAX_AP_TYPE = 7, }; +static inline const char * +ath11k_6ghz_ap_type_to_str(enum wmi_reg_6ghz_ap_type type) +{ + switch (type) { + case WMI_REG_INDOOR_AP: + return "INDOOR AP"; + case WMI_REG_STANDARD_POWER_AP: + return "STANDARD POWER AP"; + case WMI_REG_VERY_LOW_POWER_AP: + return "VERY LOW POWER AP"; + case WMI_REG_CURRENT_MAX_AP_TYPE: + return "CURRENT_MAX_AP_TYPE"; + case WMI_REG_MAX_AP_TYPE: + return "MAX_AP_TYPE"; + } + + return "unknown 6 GHz AP type"; +} + +enum wmi_reg_6ghz_client_type { + WMI_REG_DEFAULT_CLIENT = 0, + WMI_REG_SUBORDINATE_CLIENT = 1, + WMI_REG_MAX_CLIENT_TYPE = 2, + + /* add client type above, handle it in + * ath11k_6ghz_client_type_to_str() + */ +}; + +static inline const char * +ath11k_6ghz_client_type_to_str(enum wmi_reg_6ghz_client_type type) +{ + switch (type) { + case WMI_REG_DEFAULT_CLIENT: + return "DEFAULT CLIENT"; + case WMI_REG_SUBORDINATE_CLIENT: + return "SUBORDINATE CLIENT"; + case WMI_REG_MAX_CLIENT_TYPE: + return "MAX_CLIENT_TYPE"; + } + + return "unknown 6 GHz client type"; +} + +enum reg_subdomains_6ghz { + EMPTY_6GHZ = 0x0, + FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01, + FCC1_CLIENT_SP_6GHZ = 0x02, + FCC1_AP_LPI_6GHZ = 0x03, + FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ, + FCC1_AP_SP_6GHZ = 0x04, + ETSI1_LPI_6GHZ = 0x10, + ETSI1_VLP_6GHZ = 0x11, + ETSI2_LPI_6GHZ = 0x12, + ETSI2_VLP_6GHZ = 0x13, + APL1_LPI_6GHZ = 0x20, + APL1_VLP_6GHZ = 0x21, + + /* add sub-domain above, handle it in + * ath11k_sub_reg_6ghz_to_str() + */ +}; + +static inline const char * +ath11k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id) +{ + switch (sub_id) { + case EMPTY_6GHZ: + return "N/A"; + case FCC1_CLIENT_LPI_REGULAR_6GHZ: + return "FCC1_CLIENT_LPI_REGULAR_6GHZ"; + case FCC1_CLIENT_SP_6GHZ: + return "FCC1_CLIENT_SP_6GHZ"; + case FCC1_AP_LPI_6GHZ: + return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE"; + case FCC1_AP_SP_6GHZ: + return "FCC1_AP_SP_6GHZ"; + case ETSI1_LPI_6GHZ: + return "ETSI1_LPI_6GHZ"; + case ETSI1_VLP_6GHZ: + return "ETSI1_VLP_6GHZ"; + case ETSI2_LPI_6GHZ: + return "ETSI2_LPI_6GHZ"; + case ETSI2_VLP_6GHZ: + return "ETSI2_VLP_6GHZ"; + case APL1_LPI_6GHZ: + return "APL1_LPI_6GHZ"; + case APL1_VLP_6GHZ: + return "APL1_VLP_6GHZ"; + } + + return "unknown sub reg id"; +} + +enum reg_super_domain_6ghz { + FCC1_6GHZ = 0x01, + ETSI1_6GHZ = 0x02, + ETSI2_6GHZ = 0x03, + APL1_6GHZ = 0x04, + FCC1_6GHZ_CL = 0x05, + + /* add super domain above, handle it in + * ath11k_super_reg_6ghz_to_str() + */ +}; + +static inline const char * +ath11k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id) +{ + switch (domain_id) { + case FCC1_6GHZ: + return "FCC1_6GHZ"; + case ETSI1_6GHZ: + return "ETSI1_6GHZ"; + case ETSI2_6GHZ: + return "ETSI2_6GHZ"; + case APL1_6GHZ: + return "APL1_6GHZ"; + case FCC1_6GHZ_CL: + return "FCC1_6GHZ_CL"; + } + + return "unknown domain id"; +} + struct cur_reg_rule { u16 start_freq; u16 end_freq; @@ -4109,6 +4332,8 @@ struct cur_reg_rule { u8 reg_power; u8 ant_gain; u16 flags; + bool psd_flag; + s8 psd_eirp; }; struct cur_regulatory_info { @@ -4120,14 +4345,30 @@ struct cur_regulatory_info { u8 alpha2[REG_ALPHA2_LEN + 1]; u32 dfs_region; u32 phybitmap; - u32 min_bw_2g; - u32 max_bw_2g; - u32 min_bw_5g; - u32 max_bw_5g; - u32 num_2g_reg_rules; - u32 num_5g_reg_rules; - struct cur_reg_rule *reg_rules_2g_ptr; - struct cur_reg_rule *reg_rules_5g_ptr; + u32 min_bw_2ghz; + u32 max_bw_2ghz; + u32 min_bw_5ghz; + u32 max_bw_5ghz; + u32 num_2ghz_reg_rules; + u32 num_5ghz_reg_rules; + struct cur_reg_rule *reg_rules_2ghz_ptr; + struct cur_reg_rule *reg_rules_5ghz_ptr; + bool is_ext_reg_event; + enum wmi_reg_6ghz_client_type client_type; + bool rnr_tpe_usable; + bool unspecified_ap_usable; + u8 domain_code_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u8 domain_code_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 domain_code_6ghz_super_id; + u32 min_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 max_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 min_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 max_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 num_6ghz_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 num_6ghz_rules_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + struct cur_reg_rule *reg_rules_6ghz_ap_ptr[WMI_REG_CURRENT_MAX_AP_TYPE]; + struct cur_reg_rule *reg_rules_6ghz_client_ptr + [WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; }; struct wmi_reg_chan_list_cc_event { @@ -4139,12 +4380,12 @@ struct wmi_reg_chan_list_cc_event { u32 domain_code; u32 dfs_region; u32 phybitmap; - u32 min_bw_2g; - u32 max_bw_2g; - u32 min_bw_5g; - u32 max_bw_5g; - u32 num_2g_reg_rules; - u32 num_5g_reg_rules; + u32 min_bw_2ghz; + u32 max_bw_2ghz; + u32 min_bw_5ghz; + u32 max_bw_5ghz; + u32 num_2ghz_reg_rules; + u32 num_5ghz_reg_rules; } __packed; struct wmi_regulatory_rule_struct { @@ -4154,6 +4395,61 @@ struct wmi_regulatory_rule_struct { u32 flag_info; }; +#define WMI_REG_CLIENT_MAX 4 + +struct wmi_reg_chan_list_cc_ext_event { + u32 status_code; + u32 phy_id; + u32 alpha2; + u32 num_phy; + u32 country_id; + u32 domain_code; + u32 dfs_region; + u32 phybitmap; + u32 min_bw_2ghz; + u32 max_bw_2ghz; + u32 min_bw_5ghz; + u32 max_bw_5ghz; + u32 num_2ghz_reg_rules; + u32 num_5ghz_reg_rules; + u32 client_type; + u32 rnr_tpe_usable; + u32 unspecified_ap_usable; + u32 domain_code_6ghz_ap_lpi; + u32 domain_code_6ghz_ap_sp; + u32 domain_code_6ghz_ap_vlp; + u32 domain_code_6ghz_client_lpi[WMI_REG_CLIENT_MAX]; + u32 domain_code_6ghz_client_sp[WMI_REG_CLIENT_MAX]; + u32 domain_code_6ghz_client_vlp[WMI_REG_CLIENT_MAX]; + u32 domain_code_6ghz_super_id; + u32 min_bw_6ghz_ap_sp; + u32 max_bw_6ghz_ap_sp; + u32 min_bw_6ghz_ap_lpi; + u32 max_bw_6ghz_ap_lpi; + u32 min_bw_6ghz_ap_vlp; + u32 max_bw_6ghz_ap_vlp; + u32 min_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX]; + u32 max_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX]; + u32 min_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX]; + u32 max_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX]; + u32 min_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX]; + u32 max_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX]; + u32 num_6ghz_reg_rules_ap_sp; + u32 num_6ghz_reg_rules_ap_lpi; + u32 num_6ghz_reg_rules_ap_vlp; + u32 num_6ghz_reg_rules_client_sp[WMI_REG_CLIENT_MAX]; + u32 num_6ghz_reg_rules_client_lpi[WMI_REG_CLIENT_MAX]; + u32 num_6ghz_reg_rules_client_vlp[WMI_REG_CLIENT_MAX]; +} __packed; + +struct wmi_regulatory_ext_rule { + u32 tlv_header; + u32 freq_info; + u32 bw_pwr_info; + u32 flag_info; + u32 psd_power_info; +} __packed; + struct wmi_vdev_delete_resp_event { u32 vdev_id; } __packed; @@ -4542,6 +4838,8 @@ struct wmi_mgmt_tx_compl_event { u32 desc_id; u32 status; u32 pdev_id; + u32 ppdu_id; + u32 ack_rssi; } __packed; struct wmi_scan_event { @@ -5347,6 +5645,7 @@ struct target_resource_config { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; + u8 is_reg_cc_ext_event_supported; }; enum wmi_debug_log_param { |