diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath12k/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/ath12k/wmi.c | 103 |
1 files changed, 69 insertions, 34 deletions
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) |