diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath12k')
-rw-r--r-- | drivers/net/wireless/ath/ath12k/core.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/core.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/dp_rx.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/hal.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/hal.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/hw.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/hw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/mac.c | 51 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/pci.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/qmi.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/qmi.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/wmi.c | 103 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath12k/wmi.h | 10 |
13 files changed, 170 insertions, 74 deletions
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index a89e66653f04..3df8059d5512 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -706,6 +706,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); idr_destroy(&ar->txmgmt_idr); + wake_up(&ar->txmgmt_empty_waitq); } wake_up(&ab->wmi_ab.tx_credits_wq); @@ -885,6 +886,7 @@ void ath12k_core_deinit(struct ath12k_base *ab) void ath12k_core_free(struct ath12k_base *ab) { + timer_delete_sync(&ab->rx_replenish_retry); destroy_workqueue(ab->workqueue_aux); destroy_workqueue(ab->workqueue); kfree(ab); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 9439052a652e..2f93296db792 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -533,6 +533,7 @@ struct ath12k { /* protects txmgmt_idr data */ spinlock_t txmgmt_idr_lock; atomic_t num_pending_mgmt_tx; + wait_queue_head_t txmgmt_empty_waitq; /* cycle count is reported twice for each visited channel during scan. * access protected by data_lock diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index e78478a5b978..ffd9a2018610 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -193,11 +193,11 @@ static void ath12k_dp_rxdesc_set_msdu_len(struct ath12k_base *ab, ab->hw_params->hal_ops->rx_desc_set_msdu_len(desc, len); } -static bool ath12k_dp_rx_h_is_mcbc(struct ath12k_base *ab, - struct hal_rx_desc *desc) +static bool ath12k_dp_rx_h_is_da_mcbc(struct ath12k_base *ab, + struct hal_rx_desc *desc) { return (ath12k_dp_rx_h_first_msdu(ab, desc) && - ab->hw_params->hal_ops->rx_desc_is_mcbc(desc)); + ab->hw_params->hal_ops->rx_desc_is_da_mcbc(desc)); } static bool ath12k_dp_rxdesc_mac_addr2_valid(struct ath12k_base *ab, @@ -978,7 +978,19 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_ return ret; } - return ret; + if (!ab->hw_params->reoq_lut_support) { + ret = ath12k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, + peer_mac, + paddr, tid, 1, + ba_win_sz); + if (ret) { + ath12k_warn(ab, "failed to setup peer rx reorder queuefor tid %d: %d\n", + tid, ret); + return ret; + } + } + + return 0; } rx_tid->tid = tid; @@ -1362,11 +1374,6 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, * Firmware rate's control to be skipped for this? */ - if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) { - ath12k_warn(ab, "Invalid HE mcs %d peer stats", mcs); - return; - } - if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH12K_HE_MCS_MAX) { ath12k_warn(ab, "Invalid HE mcs %d peer stats", mcs); return; @@ -2201,7 +2208,7 @@ static void ath12k_dp_rx_h_mpdu(struct ath12k *ar, /* PN for multicast packets will be checked in mac80211 */ rxcb = ATH12K_SKB_RXCB(msdu); - fill_crypto_hdr = ath12k_dp_rx_h_is_mcbc(ar->ab, rx_desc); + fill_crypto_hdr = ath12k_dp_rx_h_is_da_mcbc(ar->ab, rx_desc); rxcb->is_mcbc = fill_crypto_hdr; if (rxcb->is_mcbc) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 0ec53afe9915..e7a150e7158e 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -447,10 +447,10 @@ static u8 *ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) return desc->u.qcn9274.mpdu_start.addr2; } -static bool ath12k_hw_qcn9274_rx_desc_is_mcbc(struct hal_rx_desc *desc) +static bool ath12k_hw_qcn9274_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) { - return __le32_to_cpu(desc->u.qcn9274.mpdu_start.info6) & - RX_MPDU_START_INFO6_MCAST_BCAST; + return __le16_to_cpu(desc->u.qcn9274.msdu_end.info5) & + RX_MSDU_END_INFO5_DA_IS_MCBC; } static void ath12k_hw_qcn9274_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, @@ -708,7 +708,7 @@ const struct hal_ops hal_qcn9274_ops = { .rx_desc_get_msdu_end_offset = ath12k_hw_qcn9274_rx_desc_get_msdu_end_offset, .rx_desc_mac_addr2_valid = ath12k_hw_qcn9274_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2, - .rx_desc_is_mcbc = ath12k_hw_qcn9274_rx_desc_is_mcbc, + .rx_desc_is_da_mcbc = ath12k_hw_qcn9274_rx_desc_is_da_mcbc, .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_qcn9274_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_qcn9274_rx_desc_get_mpdu_frame_ctl, @@ -887,10 +887,10 @@ static u8 *ath12k_hw_wcn7850_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) return desc->u.wcn7850.mpdu_start.addr2; } -static bool ath12k_hw_wcn7850_rx_desc_is_mcbc(struct hal_rx_desc *desc) +static bool ath12k_hw_wcn7850_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) { - return __le32_to_cpu(desc->u.wcn7850.mpdu_start.info6) & - RX_MPDU_START_INFO6_MCAST_BCAST; + return __le16_to_cpu(desc->u.wcn7850.msdu_end.info5) & + RX_MSDU_END_INFO5_DA_IS_MCBC; } static void ath12k_hw_wcn7850_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, @@ -1163,7 +1163,7 @@ const struct hal_ops hal_wcn7850_ops = { .rx_desc_get_msdu_end_offset = ath12k_hw_wcn7850_rx_desc_get_msdu_end_offset, .rx_desc_mac_addr2_valid = ath12k_hw_wcn7850_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath12k_hw_wcn7850_rx_desc_mpdu_start_addr2, - .rx_desc_is_mcbc = ath12k_hw_wcn7850_rx_desc_is_mcbc, + .rx_desc_is_da_mcbc = ath12k_hw_wcn7850_rx_desc_is_da_mcbc, .rx_desc_get_dot11_hdr = ath12k_hw_wcn7850_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_wcn7850_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_wcn7850_rx_desc_get_mpdu_frame_ctl, diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 0d4fa12ea622..66035a787c72 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1063,7 +1063,7 @@ struct hal_ops { u32 (*rx_desc_get_msdu_end_offset)(void); bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc); u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc); - bool (*rx_desc_is_mcbc)(struct hal_rx_desc *desc); + bool (*rx_desc_is_da_mcbc)(struct hal_rx_desc *desc); void (*rx_desc_get_dot11_hdr)(struct hal_rx_desc *desc, struct ieee80211_hdr *hdr); u16 (*rx_desc_get_mpdu_frame_ctl)(struct hal_rx_desc *desc); diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 1ffac7e3deaa..5991cc91cd00 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -906,6 +906,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .hal_ops = &hal_qcn9274_ops, + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01), }, { .name = "wcn7850 hw2.0", @@ -960,6 +961,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .wmi_init = ath12k_wmi_init_wcn7850, .hal_ops = &hal_wcn7850_ops, + + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) | + BIT(CNSS_PCIE_PERST_NO_PULL_V01), }, { .name = "qcn9274 hw2.0", @@ -1013,6 +1017,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .wmi_init = ath12k_wmi_init_qcn9274, .hal_ops = &hal_qcn9274_ops, + + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01), }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index e3461004188b..e6c4223c283c 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -184,6 +184,8 @@ struct ath12k_hw_params { struct ath12k_wmi_resource_config_arg *config); const struct hal_ops *hal_ops; + + u64 qmi_cnss_feature_bitmap; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ee792822b411..1bb9802ef569 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -381,7 +381,7 @@ u8 ath12k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband, } static u32 -ath12k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +ath12k_mac_max_ht_nss(const u8 *ht_mcs_mask) { int nss; @@ -393,7 +393,7 @@ ath12k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) } static u32 -ath12k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) +ath12k_mac_max_vht_nss(const u16 *vht_mcs_mask) { int nss; @@ -771,6 +771,9 @@ static int ath12k_mac_vdev_setup_sync(struct ath12k *ar) if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) return -ESHUTDOWN; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev setup timeout %d\n", + ATH12K_VDEV_SETUP_TIMEOUT_HZ); + if (!wait_for_completion_timeout(&ar->vdev_setup_done, ATH12K_VDEV_SETUP_TIMEOUT_HZ)) return -ETIMEDOUT; @@ -1303,7 +1306,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, } static bool -ath12k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +ath12k_peer_assoc_h_ht_masked(const u8 *ht_mcs_mask) { int nss; @@ -1315,7 +1318,7 @@ ath12k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) } static bool -ath12k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) +ath12k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask) { int nss; @@ -4375,6 +4378,21 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) return 0; } +static void ath12k_mgmt_over_wmi_tx_drop(struct ath12k *ar, struct sk_buff *skb) +{ + int num_mgmt; + + ieee80211_free_txskb(ar->hw, skb); + + num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); + + if (num_mgmt < 0) + WARN_ON_ONCE(1); + + if (!num_mgmt) + wake_up(&ar->txmgmt_empty_waitq); +} + int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) { struct sk_buff *msdu = skb; @@ -4391,7 +4409,7 @@ int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); - ieee80211_free_txskb(ar->hw, msdu); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); return 0; } @@ -4425,6 +4443,7 @@ static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_vif *arvif, int buf_id; int ret; + ATH12K_SKB_CB(skb)->ar = ar; spin_lock_bh(&ar->txmgmt_idr_lock); buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0, ATH12K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC); @@ -4475,7 +4494,7 @@ static void ath12k_mgmt_over_wmi_tx_purge(struct ath12k *ar) struct sk_buff *skb; while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) - ieee80211_free_txskb(ar->hw, skb); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); } static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) @@ -4490,7 +4509,7 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) skb_cb = ATH12K_SKB_CB(skb); if (!skb_cb->vif) { ath12k_warn(ar->ab, "no vif found for mgmt frame\n"); - ieee80211_free_txskb(ar->hw, skb); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); continue; } @@ -4501,16 +4520,14 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) if (ret) { ath12k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", arvif->vdev_id, ret); - ieee80211_free_txskb(ar->hw, skb); - } else { - atomic_inc(&ar->num_pending_mgmt_tx); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); } } else { ath12k_warn(ar->ab, "dropping mgmt frame for vdev %d, is_started %d\n", arvif->vdev_id, arvif->is_started); - ieee80211_free_txskb(ar->hw, skb); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); } } } @@ -4535,12 +4552,13 @@ static int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb, return -ENOSPC; } - if (skb_queue_len(q) == ATH12K_TX_MGMT_NUM_PENDING_MAX) { + if (skb_queue_len_lockless(q) >= ATH12K_TX_MGMT_NUM_PENDING_MAX) { ath12k_warn(ar->ab, "mgmt tx queue is full\n"); return -ENOSPC; } skb_queue_tail(q, skb); + atomic_inc(&ar->num_pending_mgmt_tx); ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); return 0; @@ -5910,7 +5928,6 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, } arvif->is_started = false; - mutex_unlock(&ar->conf_mutex); } ret = ath12k_mac_vdev_stop(arvif); @@ -6014,6 +6031,13 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v ATH12K_FLUSH_TIMEOUT); if (time_left == 0) ath12k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); + + time_left = wait_event_timeout(ar->txmgmt_empty_waitq, + (atomic_read(&ar->num_pending_mgmt_tx) == 0), + ATH12K_FLUSH_TIMEOUT); + if (time_left == 0) + ath12k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", + time_left); } static int @@ -6991,6 +7015,7 @@ int ath12k_mac_register(struct ath12k_base *ab) if (ret) goto err_cleanup; + init_waitqueue_head(&ar->txmgmt_empty_waitq); idr_init(&ar->txmgmt_idr); spin_lock_init(&ar->txmgmt_idr_lock); } diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 9f174daf324c..5990a55801f0 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1227,8 +1227,20 @@ static int ath12k_pci_probe(struct pci_dev *pdev, case WCN7850_DEVICE_ID: ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; - ab->hw_rev = ATH12K_HW_WCN7850_HW20; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; + ath12k_pci_read_hw_version(ab, &soc_hw_version_major, + &soc_hw_version_minor); + switch (soc_hw_version_major) { + case ATH12K_PCI_SOC_HW_VERSION_2: + ab->hw_rev = ATH12K_HW_WCN7850_HW20; + break; + default: + dev_err(&pdev->dev, + "Unknown hardware version found for WCN7850: 0x%x\n", + soc_hw_version_major); + ret = -EOPNOTSUPP; + goto err_pci_free_region; + } break; default: diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 03ba245fbee9..b510c2de1bd4 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1942,8 +1942,10 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) req.cal_done_valid = 1; req.cal_done = ab->qmi.cal_done; - req.feature_list_valid = 1; - req.feature_list = BIT(CNSS_QDSS_CFG_MISS_V01); + if (ab->hw_params->qmi_cnss_feature_bitmap) { + req.feature_list_valid = 1; + req.feature_list = ab->hw_params->qmi_cnss_feature_bitmap; + } /* BRINGUP: here we are piggybacking a lot of stuff using * internal_sleep_clock, should it be split? @@ -3056,8 +3058,7 @@ int ath12k_qmi_init_service(struct ath12k_base *ab) return ret; } - ab->qmi.event_wq = alloc_workqueue("ath12k_qmi_driver_event", - WQ_UNBOUND, 1); + ab->qmi.event_wq = alloc_ordered_workqueue("ath12k_qmi_driver_event", 0); if (!ab->qmi.event_wq) { ath12k_err(ab, "failed to allocate workqueue\n"); return -EFAULT; diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index ad87f19903db..df76149c49f5 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -189,6 +189,7 @@ struct wlfw_host_mlo_chip_info_s_v01 { enum ath12k_qmi_cnss_feature { CNSS_FEATURE_MIN_ENUM_VAL_V01 = INT_MIN, CNSS_QDSS_CFG_MISS_V01 = 3, + CNSS_PCIE_PERST_NO_PULL_V01 = 4, CNSS_MAX_FEATURE_V01 = 64, CNSS_FEATURE_MAX_ENUM_VAL_V01 = INT_MAX, }; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7ae0bb78b2b5..6512267ae4ca 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -3181,8 +3181,8 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); - wmi_cfg->host_service_flags = - cpu_to_le32(1 << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); + wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << + WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); } static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi, @@ -3390,6 +3390,10 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab) struct ath12k_wmi_base *wmi_sc = &ab->wmi_ab; struct ath12k_wmi_init_cmd_arg arg = {}; + if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, + ab->wmi_ab.svc_map)) + arg.res_cfg.is_reg_cc_ext_event_supported = true; + ab->hw_params->wmi_init(ab, &arg.res_cfg); arg.num_mem_chunks = wmi_sc->num_mem_chunks; @@ -4640,6 +4644,7 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, struct sk_buff *msdu; struct ieee80211_tx_info *info; struct ath12k_skb_cb *skb_cb; + int num_mgmt; spin_lock_bh(&ar->txmgmt_idr_lock); msdu = idr_find(&ar->txmgmt_idr, desc_id); @@ -4663,10 +4668,15 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, ieee80211_tx_status_irqsafe(ar->hw, msdu); + num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); + /* WARN when we received this event without doing any mgmt tx */ - if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) + if (num_mgmt < 0) WARN_ON_ONCE(1); + if (!num_mgmt) + wake_up(&ar->txmgmt_empty_waitq); + return 0; } @@ -5979,47 +5989,72 @@ static void ath12k_vdev_install_key_compl_event(struct ath12k_base *ab, rcu_read_unlock(); } -static void ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff *skb) +static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, + void *data) { - const void **tb; const struct wmi_service_available_event *ev; - int ret; + u32 *wmi_ext2_service_bitmap; int i, j; + u16 expected_len; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); - if (IS_ERR(tb)) { - ret = PTR_ERR(tb); - ath12k_warn(ab, "failed to parse tlv: %d\n", ret); - return; + expected_len = WMI_SERVICE_SEGMENT_BM_SIZE32 * sizeof(u32); + if (len < expected_len) { + ath12k_warn(ab, "invalid length %d for the WMI services available tag 0x%x\n", + len, tag); + return -EINVAL; } - ev = tb[WMI_TAG_SERVICE_AVAILABLE_EVENT]; - if (!ev) { - ath12k_warn(ab, "failed to fetch svc available ev"); - kfree(tb); - return; - } + switch (tag) { + case WMI_TAG_SERVICE_AVAILABLE_EVENT: + ev = (struct wmi_service_available_event *)ptr; + for (i = 0, j = WMI_MAX_SERVICE; + i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT_SERVICE; + i++) { + do { + if (le32_to_cpu(ev->wmi_service_segment_bitmap[i]) & + BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) + set_bit(j, ab->wmi_ab.svc_map); + } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + } - /* TODO: Use wmi_service_segment_offset information to get the service - * especially when more services are advertised in multiple service - * available events. - */ - for (i = 0, j = WMI_MAX_SERVICE; - i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT_SERVICE; - i++) { - do { - if (le32_to_cpu(ev->wmi_service_segment_bitmap[i]) & - BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) - set_bit(j, ab->wmi_ab.svc_map); - } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi_ext_service_bitmap 0x%x 0x%x 0x%x 0x%x", + ev->wmi_service_segment_bitmap[0], + ev->wmi_service_segment_bitmap[1], + ev->wmi_service_segment_bitmap[2], + ev->wmi_service_segment_bitmap[3]); + break; + case WMI_TAG_ARRAY_UINT32: + wmi_ext2_service_bitmap = (u32 *)ptr; + for (i = 0, j = WMI_MAX_EXT_SERVICE; + i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT2_SERVICE; + i++) { + do { + if (wmi_ext2_service_bitmap[i] & + BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) + set_bit(j, ab->wmi_ab.svc_map); + } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + } + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi_ext2_service_bitmap 0x%04x 0x%04x 0x%04x 0x%04x", + wmi_ext2_service_bitmap[0], wmi_ext2_service_bitmap[1], + wmi_ext2_service_bitmap[2], wmi_ext2_service_bitmap[3]); + break; } + return 0; +} - ath12k_dbg(ab, ATH12K_DBG_WMI, - "wmi_ext_service_bitmap 0:0x%x, 1:0x%x, 2:0x%x, 3:0x%x", - ev->wmi_service_segment_bitmap[0], ev->wmi_service_segment_bitmap[1], - ev->wmi_service_segment_bitmap[2], ev->wmi_service_segment_bitmap[3]); +static int ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff *skb) +{ + int ret; - kfree(tb); + ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len, + ath12k_wmi_tlv_services_parser, + NULL); + return ret; } static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 08a8c9e0f59f..d89c12bfb009 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2148,7 +2148,10 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219, WMI_TLV_SERVICE_EXT2_MSG = 220, - WMI_MAX_EXT_SERVICE + WMI_MAX_EXT_SERVICE = 256, + + WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281, + WMI_MAX_EXT2_SERVICE, }; enum { @@ -2333,6 +2336,7 @@ struct ath12k_wmi_resource_config_arg { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; + bool is_reg_cc_ext_event_supported; }; struct ath12k_wmi_init_cmd_arg { @@ -2682,7 +2686,7 @@ struct ath12k_wmi_ssid_params { u8 ssid[ATH12K_WMI_SSID_LEN]; } __packed; -#define ATH12K_VDEV_SETUP_TIMEOUT_HZ (1 * HZ) +#define ATH12K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) struct wmi_vdev_start_request_cmd { __le32 tlv_header; @@ -4664,7 +4668,7 @@ struct ath12k_wmi_base { struct completion service_ready; struct completion unified_ready; - DECLARE_BITMAP(svc_map, WMI_MAX_EXT_SERVICE); + DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE); wait_queue_head_t tx_credits_wq; const struct wmi_peer_flags_map *peer_flags; u32 num_mem_chunks; |