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)  |