18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "core.h"
78c2ecf20Sopenharmony_ci#include "dp_tx.h"
88c2ecf20Sopenharmony_ci#include "debug.h"
98c2ecf20Sopenharmony_ci#include "debugfs_sta.h"
108c2ecf20Sopenharmony_ci#include "hw.h"
118c2ecf20Sopenharmony_ci#include "peer.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic enum hal_tcl_encap_type
148c2ecf20Sopenharmony_ciath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
178c2ecf20Sopenharmony_ci	struct ath11k_base *ab = arvif->ar->ab;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
208c2ecf20Sopenharmony_ci		return HAL_TCL_ENCAP_TYPE_RAW;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
238c2ecf20Sopenharmony_ci		return HAL_TCL_ENCAP_TYPE_ETHERNET;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void ath11k_dp_tx_encap_nwifi(struct sk_buff *skb)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)skb->data;
318c2ecf20Sopenharmony_ci	u8 *qos_ctl;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	if (!ieee80211_is_data_qos(hdr->frame_control))
348c2ecf20Sopenharmony_ci		return;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	qos_ctl = ieee80211_get_qos_ctl(hdr);
378c2ecf20Sopenharmony_ci	memmove(skb->data + IEEE80211_QOS_CTL_LEN,
388c2ecf20Sopenharmony_ci		skb->data, (void *)qos_ctl - (void *)skb->data);
398c2ecf20Sopenharmony_ci	skb_pull(skb, IEEE80211_QOS_CTL_LEN);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	hdr = (void *)skb->data;
428c2ecf20Sopenharmony_ci	hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic u8 ath11k_dp_tx_get_tid(struct sk_buff *skb)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)skb->data;
488c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *cb = ATH11K_SKB_CB(skb);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (cb->flags & ATH11K_SKB_HW_80211_ENCAP)
518c2ecf20Sopenharmony_ci		return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
528c2ecf20Sopenharmony_ci	else if (!ieee80211_is_data_qos(hdr->frame_control))
538c2ecf20Sopenharmony_ci		return HAL_DESC_REO_NON_QOS_TID;
548c2ecf20Sopenharmony_ci	else
558c2ecf20Sopenharmony_ci		return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cienum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	switch (cipher) {
618c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
628c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_WEP_40;
638c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
648c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_WEP_104;
658c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
668c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_TKIP_MIC;
678c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
688c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_CCMP_128;
698c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
708c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_CCMP_256;
718c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
728c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_GCMP_128;
738c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
748c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_AES_GCMP_256;
758c2ecf20Sopenharmony_ci	default:
768c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_OPEN;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciint ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
818c2ecf20Sopenharmony_ci		 struct sk_buff *skb)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
848c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
858c2ecf20Sopenharmony_ci	struct hal_tx_info ti = {0};
868c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
878c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
888c2ecf20Sopenharmony_ci	struct hal_srng *tcl_ring;
898c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (void *)skb->data;
908c2ecf20Sopenharmony_ci	struct dp_tx_ring *tx_ring;
918c2ecf20Sopenharmony_ci	void *hal_tcl_desc;
928c2ecf20Sopenharmony_ci	u8 pool_id;
938c2ecf20Sopenharmony_ci	u8 hal_ring_id;
948c2ecf20Sopenharmony_ci	int ret;
958c2ecf20Sopenharmony_ci	u8 ring_selector = 0, ring_map = 0;
968c2ecf20Sopenharmony_ci	bool tcl_ring_retry;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
998c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
1028c2ecf20Sopenharmony_ci	    !ieee80211_is_data(hdr->frame_control))
1038c2ecf20Sopenharmony_ci		return -ENOTSUPP;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Let the default ring selection be based on a round robin
1088c2ecf20Sopenharmony_ci	 * fashion where one of the 3 tcl rings are selected based on
1098c2ecf20Sopenharmony_ci	 * the tcl_ring_selector counter. In case that ring
1108c2ecf20Sopenharmony_ci	 * is full/busy, we resort to other available rings.
1118c2ecf20Sopenharmony_ci	 * If all rings are full, we drop the packet.
1128c2ecf20Sopenharmony_ci	 * //TODO Add throttling logic when all rings are full
1138c2ecf20Sopenharmony_ci	 */
1148c2ecf20Sopenharmony_ci	ring_selector = atomic_inc_return(&ab->tcl_ring_selector);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_citcl_ring_sel:
1178c2ecf20Sopenharmony_ci	tcl_ring_retry = false;
1188c2ecf20Sopenharmony_ci	/* For some chip, it can only use tcl0 to tx */
1198c2ecf20Sopenharmony_ci	if (ar->ab->hw_params.tcl_0_only)
1208c2ecf20Sopenharmony_ci		ti.ring_id = 0;
1218c2ecf20Sopenharmony_ci	else
1228c2ecf20Sopenharmony_ci		ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	ring_map |= BIT(ti.ring_id);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	tx_ring = &dp->tx_ring[ti.ring_id];
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	spin_lock_bh(&tx_ring->tx_idr_lock);
1298c2ecf20Sopenharmony_ci	ret = idr_alloc(&tx_ring->txbuf_idr, skb, 0,
1308c2ecf20Sopenharmony_ci			DP_TX_IDR_SIZE - 1, GFP_ATOMIC);
1318c2ecf20Sopenharmony_ci	spin_unlock_bh(&tx_ring->tx_idr_lock);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (ret < 0) {
1348c2ecf20Sopenharmony_ci		if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1)) {
1358c2ecf20Sopenharmony_ci			atomic_inc(&ab->soc_stats.tx_err.misc_fail);
1368c2ecf20Sopenharmony_ci			return -ENOSPC;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		/* Check if the next ring is available */
1408c2ecf20Sopenharmony_ci		ring_selector++;
1418c2ecf20Sopenharmony_ci		goto tcl_ring_sel;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	ti.desc_id = FIELD_PREP(DP_TX_DESC_ID_MAC_ID, ar->pdev_idx) |
1458c2ecf20Sopenharmony_ci		     FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, ret) |
1468c2ecf20Sopenharmony_ci		     FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id);
1478c2ecf20Sopenharmony_ci	ti.encap_type = ath11k_dp_tx_get_encap_type(arvif, skb);
1488c2ecf20Sopenharmony_ci	ti.meta_data_flags = arvif->tcl_metadata;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) {
1518c2ecf20Sopenharmony_ci		if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) {
1528c2ecf20Sopenharmony_ci			ti.encrypt_type =
1538c2ecf20Sopenharmony_ci				ath11k_dp_tx_get_encrypt_type(skb_cb->cipher);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci			if (ieee80211_has_protected(hdr->frame_control))
1568c2ecf20Sopenharmony_ci				skb_put(skb, IEEE80211_CCMP_MIC_LEN);
1578c2ecf20Sopenharmony_ci		} else {
1588c2ecf20Sopenharmony_ci			ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
1598c2ecf20Sopenharmony_ci		}
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	ti.addr_search_flags = arvif->hal_addr_search_flags;
1638c2ecf20Sopenharmony_ci	ti.search_type = arvif->search_type;
1648c2ecf20Sopenharmony_ci	ti.type = HAL_TCL_DESC_TYPE_BUFFER;
1658c2ecf20Sopenharmony_ci	ti.pkt_offset = 0;
1668c2ecf20Sopenharmony_ci	ti.lmac_id = ar->lmac_id;
1678c2ecf20Sopenharmony_ci	ti.bss_ast_hash = arvif->ast_hash;
1688c2ecf20Sopenharmony_ci	ti.dscp_tid_tbl_idx = 0;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL &&
1718c2ecf20Sopenharmony_ci	    ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) {
1728c2ecf20Sopenharmony_ci		ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) |
1738c2ecf20Sopenharmony_ci			     FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) |
1748c2ecf20Sopenharmony_ci			     FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) |
1758c2ecf20Sopenharmony_ci			     FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP4_CKSUM_EN, 1) |
1768c2ecf20Sopenharmony_ci			     FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP6_CKSUM_EN, 1);
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (ieee80211_vif_is_mesh(arvif->vif))
1808c2ecf20Sopenharmony_ci		ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_MESH_ENABLE, 1);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE, 1);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	ti.tid = ath11k_dp_tx_get_tid(skb);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	switch (ti.encap_type) {
1878c2ecf20Sopenharmony_ci	case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
1888c2ecf20Sopenharmony_ci		ath11k_dp_tx_encap_nwifi(skb);
1898c2ecf20Sopenharmony_ci		break;
1908c2ecf20Sopenharmony_ci	case HAL_TCL_ENCAP_TYPE_RAW:
1918c2ecf20Sopenharmony_ci		if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) {
1928c2ecf20Sopenharmony_ci			ret = -EINVAL;
1938c2ecf20Sopenharmony_ci			goto fail_remove_idr;
1948c2ecf20Sopenharmony_ci		}
1958c2ecf20Sopenharmony_ci		break;
1968c2ecf20Sopenharmony_ci	case HAL_TCL_ENCAP_TYPE_ETHERNET:
1978c2ecf20Sopenharmony_ci		/* no need to encap */
1988c2ecf20Sopenharmony_ci		break;
1998c2ecf20Sopenharmony_ci	case HAL_TCL_ENCAP_TYPE_802_3:
2008c2ecf20Sopenharmony_ci	default:
2018c2ecf20Sopenharmony_ci		/* TODO: Take care of other encap modes as well */
2028c2ecf20Sopenharmony_ci		ret = -EINVAL;
2038c2ecf20Sopenharmony_ci		atomic_inc(&ab->soc_stats.tx_err.misc_fail);
2048c2ecf20Sopenharmony_ci		goto fail_remove_idr;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
2088c2ecf20Sopenharmony_ci	if (dma_mapping_error(ab->dev, ti.paddr)) {
2098c2ecf20Sopenharmony_ci		atomic_inc(&ab->soc_stats.tx_err.misc_fail);
2108c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to DMA map data Tx buffer\n");
2118c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2128c2ecf20Sopenharmony_ci		goto fail_remove_idr;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ti.data_len = skb->len;
2168c2ecf20Sopenharmony_ci	skb_cb->paddr = ti.paddr;
2178c2ecf20Sopenharmony_ci	skb_cb->vif = arvif->vif;
2188c2ecf20Sopenharmony_ci	skb_cb->ar = ar;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	hal_ring_id = tx_ring->tcl_data_ring.ring_id;
2218c2ecf20Sopenharmony_ci	tcl_ring = &ab->hal.srng_list[hal_ring_id];
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	spin_lock_bh(&tcl_ring->lock);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, tcl_ring);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, tcl_ring);
2288c2ecf20Sopenharmony_ci	if (!hal_tcl_desc) {
2298c2ecf20Sopenharmony_ci		/* NOTE: It is highly unlikely we'll be running out of tcl_ring
2308c2ecf20Sopenharmony_ci		 * desc because the desc is directly enqueued onto hw queue.
2318c2ecf20Sopenharmony_ci		 */
2328c2ecf20Sopenharmony_ci		ath11k_hal_srng_access_end(ab, tcl_ring);
2338c2ecf20Sopenharmony_ci		ab->soc_stats.tx_err.desc_na[ti.ring_id]++;
2348c2ecf20Sopenharmony_ci		spin_unlock_bh(&tcl_ring->lock);
2358c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		/* Checking for available tcl descritors in another ring in
2388c2ecf20Sopenharmony_ci		 * case of failure due to full tcl ring now, is better than
2398c2ecf20Sopenharmony_ci		 * checking this ring earlier for each pkt tx.
2408c2ecf20Sopenharmony_ci		 * Restart ring selection if some rings are not checked yet.
2418c2ecf20Sopenharmony_ci		 */
2428c2ecf20Sopenharmony_ci		if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1) &&
2438c2ecf20Sopenharmony_ci		    !ar->ab->hw_params.tcl_0_only) {
2448c2ecf20Sopenharmony_ci			tcl_ring_retry = true;
2458c2ecf20Sopenharmony_ci			ring_selector++;
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		goto fail_unmap_dma;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	ath11k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc +
2528c2ecf20Sopenharmony_ci					 sizeof(struct hal_tlv_hdr), &ti);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, tcl_ring);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	ath11k_dp_shadow_start_timer(ab, tcl_ring, &dp->tx_ring_timer[ti.ring_id]);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	spin_unlock_bh(&tcl_ring->lock);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	ath11k_dbg_dump(ab, ATH11K_DBG_DP_TX, NULL, "dp tx msdu: ",
2618c2ecf20Sopenharmony_ci			skb->data, skb->len);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	atomic_inc(&ar->dp.num_tx_pending);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return 0;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cifail_unmap_dma:
2688c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cifail_remove_idr:
2718c2ecf20Sopenharmony_ci	spin_lock_bh(&tx_ring->tx_idr_lock);
2728c2ecf20Sopenharmony_ci	idr_remove(&tx_ring->txbuf_idr,
2738c2ecf20Sopenharmony_ci		   FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ti.desc_id));
2748c2ecf20Sopenharmony_ci	spin_unlock_bh(&tx_ring->tx_idr_lock);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (tcl_ring_retry)
2778c2ecf20Sopenharmony_ci		goto tcl_ring_sel;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	return ret;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic void ath11k_dp_tx_free_txbuf(struct ath11k_base *ab, u8 mac_id,
2838c2ecf20Sopenharmony_ci				    int msdu_id,
2848c2ecf20Sopenharmony_ci				    struct dp_tx_ring *tx_ring)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct ath11k *ar;
2878c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
2888c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	spin_lock_bh(&tx_ring->tx_idr_lock);
2918c2ecf20Sopenharmony_ci	msdu = idr_find(&tx_ring->txbuf_idr, msdu_id);
2928c2ecf20Sopenharmony_ci	if (!msdu) {
2938c2ecf20Sopenharmony_ci		ath11k_warn(ab, "tx completion for unknown msdu_id %d\n",
2948c2ecf20Sopenharmony_ci			    msdu_id);
2958c2ecf20Sopenharmony_ci		spin_unlock_bh(&tx_ring->tx_idr_lock);
2968c2ecf20Sopenharmony_ci		return;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	skb_cb = ATH11K_SKB_CB(msdu);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	idr_remove(&tx_ring->txbuf_idr, msdu_id);
3028c2ecf20Sopenharmony_ci	spin_unlock_bh(&tx_ring->tx_idr_lock);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
3058c2ecf20Sopenharmony_ci	dev_kfree_skb_any(msdu);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	ar = ab->pdevs[mac_id].ar;
3088c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&ar->dp.num_tx_pending))
3098c2ecf20Sopenharmony_ci		wake_up(&ar->dp.tx_empty_waitq);
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic void
3138c2ecf20Sopenharmony_ciath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab,
3148c2ecf20Sopenharmony_ci				 struct dp_tx_ring *tx_ring,
3158c2ecf20Sopenharmony_ci				 struct ath11k_dp_htt_wbm_tx_status *ts)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
3188c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info;
3198c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb;
3208c2ecf20Sopenharmony_ci	struct ath11k *ar;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	spin_lock_bh(&tx_ring->tx_idr_lock);
3238c2ecf20Sopenharmony_ci	msdu = idr_find(&tx_ring->txbuf_idr, ts->msdu_id);
3248c2ecf20Sopenharmony_ci	if (!msdu) {
3258c2ecf20Sopenharmony_ci		ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n",
3268c2ecf20Sopenharmony_ci			    ts->msdu_id);
3278c2ecf20Sopenharmony_ci		spin_unlock_bh(&tx_ring->tx_idr_lock);
3288c2ecf20Sopenharmony_ci		return;
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	skb_cb = ATH11K_SKB_CB(msdu);
3328c2ecf20Sopenharmony_ci	info = IEEE80211_SKB_CB(msdu);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	ar = skb_cb->ar;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	idr_remove(&tx_ring->txbuf_idr, ts->msdu_id);
3378c2ecf20Sopenharmony_ci	spin_unlock_bh(&tx_ring->tx_idr_lock);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&ar->dp.num_tx_pending))
3408c2ecf20Sopenharmony_ci		wake_up(&ar->dp.tx_empty_waitq);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	memset(&info->status, 0, sizeof(info->status));
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (ts->acked) {
3478c2ecf20Sopenharmony_ci		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
3488c2ecf20Sopenharmony_ci			info->flags |= IEEE80211_TX_STAT_ACK;
3498c2ecf20Sopenharmony_ci			info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR +
3508c2ecf20Sopenharmony_ci						  ts->ack_rssi;
3518c2ecf20Sopenharmony_ci			info->status.is_valid_ack_signal = true;
3528c2ecf20Sopenharmony_ci		} else {
3538c2ecf20Sopenharmony_ci			info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	ieee80211_tx_status(ar->hw, msdu);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic void
3618c2ecf20Sopenharmony_ciath11k_dp_tx_process_htt_tx_complete(struct ath11k_base *ab,
3628c2ecf20Sopenharmony_ci				     void *desc, u8 mac_id,
3638c2ecf20Sopenharmony_ci				     u32 msdu_id, struct dp_tx_ring *tx_ring)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct htt_tx_wbm_completion *status_desc;
3668c2ecf20Sopenharmony_ci	struct ath11k_dp_htt_wbm_tx_status ts = {0};
3678c2ecf20Sopenharmony_ci	enum hal_wbm_htt_tx_comp_status wbm_status;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	wbm_status = FIELD_GET(HTT_TX_WBM_COMP_INFO0_STATUS,
3728c2ecf20Sopenharmony_ci			       status_desc->info0);
3738c2ecf20Sopenharmony_ci	switch (wbm_status) {
3748c2ecf20Sopenharmony_ci	case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK:
3758c2ecf20Sopenharmony_ci	case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
3768c2ecf20Sopenharmony_ci	case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
3778c2ecf20Sopenharmony_ci		ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);
3788c2ecf20Sopenharmony_ci		ts.msdu_id = msdu_id;
3798c2ecf20Sopenharmony_ci		ts.ack_rssi = FIELD_GET(HTT_TX_WBM_COMP_INFO1_ACK_RSSI,
3808c2ecf20Sopenharmony_ci					status_desc->info1);
3818c2ecf20Sopenharmony_ci		ath11k_dp_tx_htt_tx_complete_buf(ab, tx_ring, &ts);
3828c2ecf20Sopenharmony_ci		break;
3838c2ecf20Sopenharmony_ci	case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:
3848c2ecf20Sopenharmony_ci	case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:
3858c2ecf20Sopenharmony_ci		ath11k_dp_tx_free_txbuf(ab, mac_id, msdu_id, tx_ring);
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY:
3888c2ecf20Sopenharmony_ci		/* This event is to be handled only when the driver decides to
3898c2ecf20Sopenharmony_ci		 * use WDS offload functionality.
3908c2ecf20Sopenharmony_ci		 */
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci	default:
3938c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Unknown htt tx status %d\n", wbm_status);
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic void ath11k_dp_tx_cache_peer_stats(struct ath11k *ar,
3998c2ecf20Sopenharmony_ci					  struct sk_buff *msdu,
4008c2ecf20Sopenharmony_ci					  struct hal_tx_status *ts)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (ts->try_cnt > 1) {
4058c2ecf20Sopenharmony_ci		peer_stats->retry_pkts += ts->try_cnt - 1;
4068c2ecf20Sopenharmony_ci		peer_stats->retry_bytes += (ts->try_cnt - 1) * msdu->len;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		if (ts->status != HAL_WBM_TQM_REL_REASON_FRAME_ACKED) {
4098c2ecf20Sopenharmony_ci			peer_stats->failed_pkts += 1;
4108c2ecf20Sopenharmony_ci			peer_stats->failed_bytes += msdu->len;
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
4168c2ecf20Sopenharmony_ci				       struct sk_buff *msdu,
4178c2ecf20Sopenharmony_ci				       struct hal_tx_status *ts)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
4208c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info;
4218c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) {
4248c2ecf20Sopenharmony_ci		/* Must not happen */
4258c2ecf20Sopenharmony_ci		return;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	skb_cb = ATH11K_SKB_CB(msdu);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	rcu_read_lock();
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) {
4358c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
4368c2ecf20Sopenharmony_ci		goto exit;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (!skb_cb->vif) {
4408c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
4418c2ecf20Sopenharmony_ci		goto exit;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	info = IEEE80211_SKB_CB(msdu);
4458c2ecf20Sopenharmony_ci	memset(&info->status, 0, sizeof(info->status));
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* skip tx rate update from ieee80211_status*/
4488c2ecf20Sopenharmony_ci	info->status.rates[0].idx = -1;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED &&
4518c2ecf20Sopenharmony_ci	    !(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
4528c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
4538c2ecf20Sopenharmony_ci		info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR +
4548c2ecf20Sopenharmony_ci					  ts->ack_rssi;
4558c2ecf20Sopenharmony_ci		info->status.is_valid_ack_signal = true;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (ts->status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX &&
4598c2ecf20Sopenharmony_ci	    (info->flags & IEEE80211_TX_CTL_NO_ACK))
4608c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
4638c2ecf20Sopenharmony_ci		if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) {
4648c2ecf20Sopenharmony_ci			if (ar->last_ppdu_id == 0) {
4658c2ecf20Sopenharmony_ci				ar->last_ppdu_id = ts->ppdu_id;
4668c2ecf20Sopenharmony_ci			} else if (ar->last_ppdu_id == ts->ppdu_id ||
4678c2ecf20Sopenharmony_ci				   ar->cached_ppdu_id == ar->last_ppdu_id) {
4688c2ecf20Sopenharmony_ci				ar->cached_ppdu_id = ar->last_ppdu_id;
4698c2ecf20Sopenharmony_ci				ar->cached_stats.is_ampdu = true;
4708c2ecf20Sopenharmony_ci				ath11k_debugfs_sta_update_txcompl(ar, msdu, ts);
4718c2ecf20Sopenharmony_ci				memset(&ar->cached_stats, 0,
4728c2ecf20Sopenharmony_ci				       sizeof(struct ath11k_per_peer_tx_stats));
4738c2ecf20Sopenharmony_ci			} else {
4748c2ecf20Sopenharmony_ci				ar->cached_stats.is_ampdu = false;
4758c2ecf20Sopenharmony_ci				ath11k_debugfs_sta_update_txcompl(ar, msdu, ts);
4768c2ecf20Sopenharmony_ci				memset(&ar->cached_stats, 0,
4778c2ecf20Sopenharmony_ci				       sizeof(struct ath11k_per_peer_tx_stats));
4788c2ecf20Sopenharmony_ci			}
4798c2ecf20Sopenharmony_ci			ar->last_ppdu_id = ts->ppdu_id;
4808c2ecf20Sopenharmony_ci		}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci		ath11k_dp_tx_cache_peer_stats(ar, msdu, ts);
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	/* NOTE: Tx rate status reporting. Tx completion status does not have
4868c2ecf20Sopenharmony_ci	 * necessary information (for example nss) to build the tx rate.
4878c2ecf20Sopenharmony_ci	 * Might end up reporting it out-of-band from HTT stats.
4888c2ecf20Sopenharmony_ci	 */
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	ieee80211_tx_status(ar->hw, msdu);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ciexit:
4938c2ecf20Sopenharmony_ci	rcu_read_unlock();
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab,
4978c2ecf20Sopenharmony_ci					     struct hal_wbm_release_ring *desc,
4988c2ecf20Sopenharmony_ci					     struct hal_tx_status *ts)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	ts->buf_rel_source =
5018c2ecf20Sopenharmony_ci		FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0);
5028c2ecf20Sopenharmony_ci	if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW &&
5038c2ecf20Sopenharmony_ci	    ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)
5048c2ecf20Sopenharmony_ci		return;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)
5078c2ecf20Sopenharmony_ci		return;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON,
5108c2ecf20Sopenharmony_ci			       desc->info0);
5118c2ecf20Sopenharmony_ci	ts->ppdu_id = FIELD_GET(HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER,
5128c2ecf20Sopenharmony_ci				desc->info1);
5138c2ecf20Sopenharmony_ci	ts->try_cnt = FIELD_GET(HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT,
5148c2ecf20Sopenharmony_ci				desc->info1);
5158c2ecf20Sopenharmony_ci	ts->ack_rssi = FIELD_GET(HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI,
5168c2ecf20Sopenharmony_ci				 desc->info2);
5178c2ecf20Sopenharmony_ci	if (desc->info2 & HAL_WBM_RELEASE_INFO2_FIRST_MSDU)
5188c2ecf20Sopenharmony_ci		ts->flags |= HAL_TX_STATUS_FLAGS_FIRST_MSDU;
5198c2ecf20Sopenharmony_ci	ts->peer_id = FIELD_GET(HAL_WBM_RELEASE_INFO3_PEER_ID, desc->info3);
5208c2ecf20Sopenharmony_ci	ts->tid = FIELD_GET(HAL_WBM_RELEASE_INFO3_TID, desc->info3);
5218c2ecf20Sopenharmony_ci	if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_VALID)
5228c2ecf20Sopenharmony_ci		ts->rate_stats = desc->rate_stats.info0;
5238c2ecf20Sopenharmony_ci	else
5248c2ecf20Sopenharmony_ci		ts->rate_stats = 0;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_civoid ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct ath11k *ar;
5308c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
5318c2ecf20Sopenharmony_ci	int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id;
5328c2ecf20Sopenharmony_ci	struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id];
5338c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
5348c2ecf20Sopenharmony_ci	struct hal_tx_status ts = { 0 };
5358c2ecf20Sopenharmony_ci	struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id];
5368c2ecf20Sopenharmony_ci	u32 *desc;
5378c2ecf20Sopenharmony_ci	u32 msdu_id;
5388c2ecf20Sopenharmony_ci	u8 mac_id;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	spin_lock_bh(&status_ring->lock);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, status_ring);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	while ((ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) !=
5458c2ecf20Sopenharmony_ci		tx_ring->tx_status_tail) &&
5468c2ecf20Sopenharmony_ci	       (desc = ath11k_hal_srng_dst_get_next_entry(ab, status_ring))) {
5478c2ecf20Sopenharmony_ci		memcpy(&tx_ring->tx_status[tx_ring->tx_status_head],
5488c2ecf20Sopenharmony_ci		       desc, sizeof(struct hal_wbm_release_ring));
5498c2ecf20Sopenharmony_ci		tx_ring->tx_status_head =
5508c2ecf20Sopenharmony_ci			ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head);
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if ((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) &&
5548c2ecf20Sopenharmony_ci	    (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) {
5558c2ecf20Sopenharmony_ci		/* TODO: Process pending tx_status messages when kfifo_is_full() */
5568c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n");
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, status_ring);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	spin_unlock_bh(&status_ring->lock);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	while (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail) != tx_ring->tx_status_head) {
5648c2ecf20Sopenharmony_ci		struct hal_wbm_release_ring *tx_status;
5658c2ecf20Sopenharmony_ci		u32 desc_id;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		tx_ring->tx_status_tail =
5688c2ecf20Sopenharmony_ci			ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail);
5698c2ecf20Sopenharmony_ci		tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail];
5708c2ecf20Sopenharmony_ci		ath11k_dp_tx_status_parse(ab, tx_status, &ts);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		desc_id = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
5738c2ecf20Sopenharmony_ci				    tx_status->buf_addr_info.info1);
5748c2ecf20Sopenharmony_ci		mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id);
5758c2ecf20Sopenharmony_ci		msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci		if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) {
5788c2ecf20Sopenharmony_ci			ath11k_dp_tx_process_htt_tx_complete(ab,
5798c2ecf20Sopenharmony_ci							     (void *)tx_status,
5808c2ecf20Sopenharmony_ci							     mac_id, msdu_id,
5818c2ecf20Sopenharmony_ci							     tx_ring);
5828c2ecf20Sopenharmony_ci			continue;
5838c2ecf20Sopenharmony_ci		}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		spin_lock_bh(&tx_ring->tx_idr_lock);
5868c2ecf20Sopenharmony_ci		msdu = idr_find(&tx_ring->txbuf_idr, msdu_id);
5878c2ecf20Sopenharmony_ci		if (!msdu) {
5888c2ecf20Sopenharmony_ci			ath11k_warn(ab, "tx completion for unknown msdu_id %d\n",
5898c2ecf20Sopenharmony_ci				    msdu_id);
5908c2ecf20Sopenharmony_ci			spin_unlock_bh(&tx_ring->tx_idr_lock);
5918c2ecf20Sopenharmony_ci			continue;
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci		idr_remove(&tx_ring->txbuf_idr, msdu_id);
5948c2ecf20Sopenharmony_ci		spin_unlock_bh(&tx_ring->tx_idr_lock);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		ar = ab->pdevs[mac_id].ar;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		if (atomic_dec_and_test(&ar->dp.num_tx_pending))
5998c2ecf20Sopenharmony_ci			wake_up(&ar->dp.tx_empty_waitq);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		ath11k_dp_tx_complete_msdu(ar, msdu, &ts);
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ciint ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid,
6068c2ecf20Sopenharmony_ci			      enum hal_reo_cmd_type type,
6078c2ecf20Sopenharmony_ci			      struct ath11k_hal_reo_cmd *cmd,
6088c2ecf20Sopenharmony_ci			      void (*cb)(struct ath11k_dp *, void *,
6098c2ecf20Sopenharmony_ci					 enum hal_reo_cmd_status))
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
6128c2ecf20Sopenharmony_ci	struct dp_reo_cmd *dp_cmd;
6138c2ecf20Sopenharmony_ci	struct hal_srng *cmd_ring;
6148c2ecf20Sopenharmony_ci	int cmd_num;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id];
6178c2ecf20Sopenharmony_ci	cmd_num = ath11k_hal_reo_cmd_send(ab, cmd_ring, type, cmd);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	/* cmd_num should start from 1, during failure return the error code */
6208c2ecf20Sopenharmony_ci	if (cmd_num < 0)
6218c2ecf20Sopenharmony_ci		return cmd_num;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	/* reo cmd ring descriptors has cmd_num starting from 1 */
6248c2ecf20Sopenharmony_ci	if (cmd_num == 0)
6258c2ecf20Sopenharmony_ci		return -EINVAL;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (!cb)
6288c2ecf20Sopenharmony_ci		return 0;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	/* Can this be optimized so that we keep the pending command list only
6318c2ecf20Sopenharmony_ci	 * for tid delete command to free up the resoruce on the command status
6328c2ecf20Sopenharmony_ci	 * indication?
6338c2ecf20Sopenharmony_ci	 */
6348c2ecf20Sopenharmony_ci	dp_cmd = kzalloc(sizeof(*dp_cmd), GFP_ATOMIC);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	if (!dp_cmd)
6378c2ecf20Sopenharmony_ci		return -ENOMEM;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	memcpy(&dp_cmd->data, rx_tid, sizeof(struct dp_rx_tid));
6408c2ecf20Sopenharmony_ci	dp_cmd->cmd_num = cmd_num;
6418c2ecf20Sopenharmony_ci	dp_cmd->handler = cb;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	spin_lock_bh(&dp->reo_cmd_lock);
6448c2ecf20Sopenharmony_ci	list_add_tail(&dp_cmd->list, &dp->reo_cmd_list);
6458c2ecf20Sopenharmony_ci	spin_unlock_bh(&dp->reo_cmd_lock);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return 0;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic int
6518c2ecf20Sopenharmony_ciath11k_dp_tx_get_ring_id_type(struct ath11k_base *ab,
6528c2ecf20Sopenharmony_ci			      int mac_id, u32 ring_id,
6538c2ecf20Sopenharmony_ci			      enum hal_ring_type ring_type,
6548c2ecf20Sopenharmony_ci			      enum htt_srng_ring_type *htt_ring_type,
6558c2ecf20Sopenharmony_ci			      enum htt_srng_ring_id *htt_ring_id)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	int lmac_ring_id_offset = 0;
6588c2ecf20Sopenharmony_ci	int ret = 0;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	switch (ring_type) {
6618c2ecf20Sopenharmony_ci	case HAL_RXDMA_BUF:
6628c2ecf20Sopenharmony_ci		lmac_ring_id_offset = mac_id * HAL_SRNG_RINGS_PER_LMAC;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci		/* for QCA6390, host fills rx buffer to fw and fw fills to
6658c2ecf20Sopenharmony_ci		 * rxbuf ring for each rxdma
6668c2ecf20Sopenharmony_ci		 */
6678c2ecf20Sopenharmony_ci		if (!ab->hw_params.rx_mac_buf_ring) {
6688c2ecf20Sopenharmony_ci			if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF +
6698c2ecf20Sopenharmony_ci					  lmac_ring_id_offset) ||
6708c2ecf20Sopenharmony_ci				ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF +
6718c2ecf20Sopenharmony_ci					lmac_ring_id_offset))) {
6728c2ecf20Sopenharmony_ci				ret = -EINVAL;
6738c2ecf20Sopenharmony_ci			}
6748c2ecf20Sopenharmony_ci			*htt_ring_id = HTT_RXDMA_HOST_BUF_RING;
6758c2ecf20Sopenharmony_ci			*htt_ring_type = HTT_SW_TO_HW_RING;
6768c2ecf20Sopenharmony_ci		} else {
6778c2ecf20Sopenharmony_ci			if (ring_id == HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF) {
6788c2ecf20Sopenharmony_ci				*htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING;
6798c2ecf20Sopenharmony_ci				*htt_ring_type = HTT_SW_TO_SW_RING;
6808c2ecf20Sopenharmony_ci			} else {
6818c2ecf20Sopenharmony_ci				*htt_ring_id = HTT_RXDMA_HOST_BUF_RING;
6828c2ecf20Sopenharmony_ci				*htt_ring_type = HTT_SW_TO_HW_RING;
6838c2ecf20Sopenharmony_ci			}
6848c2ecf20Sopenharmony_ci		}
6858c2ecf20Sopenharmony_ci		break;
6868c2ecf20Sopenharmony_ci	case HAL_RXDMA_DST:
6878c2ecf20Sopenharmony_ci		*htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING;
6888c2ecf20Sopenharmony_ci		*htt_ring_type = HTT_HW_TO_SW_RING;
6898c2ecf20Sopenharmony_ci		break;
6908c2ecf20Sopenharmony_ci	case HAL_RXDMA_MONITOR_BUF:
6918c2ecf20Sopenharmony_ci		*htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING;
6928c2ecf20Sopenharmony_ci		*htt_ring_type = HTT_SW_TO_HW_RING;
6938c2ecf20Sopenharmony_ci		break;
6948c2ecf20Sopenharmony_ci	case HAL_RXDMA_MONITOR_STATUS:
6958c2ecf20Sopenharmony_ci		*htt_ring_id = HTT_RXDMA_MONITOR_STATUS_RING;
6968c2ecf20Sopenharmony_ci		*htt_ring_type = HTT_SW_TO_HW_RING;
6978c2ecf20Sopenharmony_ci		break;
6988c2ecf20Sopenharmony_ci	case HAL_RXDMA_MONITOR_DST:
6998c2ecf20Sopenharmony_ci		*htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING;
7008c2ecf20Sopenharmony_ci		*htt_ring_type = HTT_HW_TO_SW_RING;
7018c2ecf20Sopenharmony_ci		break;
7028c2ecf20Sopenharmony_ci	case HAL_RXDMA_MONITOR_DESC:
7038c2ecf20Sopenharmony_ci		*htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING;
7048c2ecf20Sopenharmony_ci		*htt_ring_type = HTT_SW_TO_HW_RING;
7058c2ecf20Sopenharmony_ci		break;
7068c2ecf20Sopenharmony_ci	default:
7078c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Unsupported ring type in DP :%d\n", ring_type);
7088c2ecf20Sopenharmony_ci		ret = -EINVAL;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci	return ret;
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ciint ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id,
7148c2ecf20Sopenharmony_ci				int mac_id, enum hal_ring_type ring_type)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct htt_srng_setup_cmd *cmd;
7178c2ecf20Sopenharmony_ci	struct hal_srng *srng = &ab->hal.srng_list[ring_id];
7188c2ecf20Sopenharmony_ci	struct hal_srng_params params;
7198c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7208c2ecf20Sopenharmony_ci	u32 ring_entry_sz;
7218c2ecf20Sopenharmony_ci	int len = sizeof(*cmd);
7228c2ecf20Sopenharmony_ci	dma_addr_t hp_addr, tp_addr;
7238c2ecf20Sopenharmony_ci	enum htt_srng_ring_type htt_ring_type;
7248c2ecf20Sopenharmony_ci	enum htt_srng_ring_id htt_ring_id;
7258c2ecf20Sopenharmony_ci	int ret;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	skb = ath11k_htc_alloc_skb(ab, len);
7288c2ecf20Sopenharmony_ci	if (!skb)
7298c2ecf20Sopenharmony_ci		return -ENOMEM;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(params));
7328c2ecf20Sopenharmony_ci	ath11k_hal_srng_get_params(ab, srng, &params);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	hp_addr = ath11k_hal_srng_get_hp_addr(ab, srng);
7358c2ecf20Sopenharmony_ci	tp_addr = ath11k_hal_srng_get_tp_addr(ab, srng);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id,
7388c2ecf20Sopenharmony_ci					    ring_type, &htt_ring_type,
7398c2ecf20Sopenharmony_ci					    &htt_ring_id);
7408c2ecf20Sopenharmony_ci	if (ret)
7418c2ecf20Sopenharmony_ci		goto err_free;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	skb_put(skb, len);
7448c2ecf20Sopenharmony_ci	cmd = (struct htt_srng_setup_cmd *)skb->data;
7458c2ecf20Sopenharmony_ci	cmd->info0 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_MSG_TYPE,
7468c2ecf20Sopenharmony_ci				HTT_H2T_MSG_TYPE_SRING_SETUP);
7478c2ecf20Sopenharmony_ci	if (htt_ring_type == HTT_SW_TO_HW_RING ||
7488c2ecf20Sopenharmony_ci	    htt_ring_type == HTT_HW_TO_SW_RING)
7498c2ecf20Sopenharmony_ci		cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID,
7508c2ecf20Sopenharmony_ci					 DP_SW2HW_MACID(mac_id));
7518c2ecf20Sopenharmony_ci	else
7528c2ecf20Sopenharmony_ci		cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID,
7538c2ecf20Sopenharmony_ci					 mac_id);
7548c2ecf20Sopenharmony_ci	cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_TYPE,
7558c2ecf20Sopenharmony_ci				 htt_ring_type);
7568c2ecf20Sopenharmony_ci	cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_ID, htt_ring_id);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	cmd->ring_base_addr_lo = params.ring_base_paddr &
7598c2ecf20Sopenharmony_ci				 HAL_ADDR_LSB_REG_MASK;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	cmd->ring_base_addr_hi = (u64)params.ring_base_paddr >>
7628c2ecf20Sopenharmony_ci				 HAL_ADDR_MSB_REG_SHIFT;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	ret = ath11k_hal_srng_get_entrysize(ab, ring_type);
7658c2ecf20Sopenharmony_ci	if (ret < 0)
7668c2ecf20Sopenharmony_ci		goto err_free;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	ring_entry_sz = ret;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	ring_entry_sz >>= 2;
7718c2ecf20Sopenharmony_ci	cmd->info1 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_ENTRY_SIZE,
7728c2ecf20Sopenharmony_ci				ring_entry_sz);
7738c2ecf20Sopenharmony_ci	cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_SIZE,
7748c2ecf20Sopenharmony_ci				 params.num_entries * ring_entry_sz);
7758c2ecf20Sopenharmony_ci	cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP,
7768c2ecf20Sopenharmony_ci				 !!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP));
7778c2ecf20Sopenharmony_ci	cmd->info1 |= FIELD_PREP(
7788c2ecf20Sopenharmony_ci			HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_TLV_SWAP,
7798c2ecf20Sopenharmony_ci			!!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP));
7808c2ecf20Sopenharmony_ci	cmd->info1 |= FIELD_PREP(
7818c2ecf20Sopenharmony_ci			HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_HOST_FW_SWAP,
7828c2ecf20Sopenharmony_ci			!!(params.flags & HAL_SRNG_FLAGS_RING_PTR_SWAP));
7838c2ecf20Sopenharmony_ci	if (htt_ring_type == HTT_SW_TO_HW_RING)
7848c2ecf20Sopenharmony_ci		cmd->info1 |= HTT_SRNG_SETUP_CMD_INFO1_RING_LOOP_CNT_DIS;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	cmd->ring_head_off32_remote_addr_lo = hp_addr & HAL_ADDR_LSB_REG_MASK;
7878c2ecf20Sopenharmony_ci	cmd->ring_head_off32_remote_addr_hi = (u64)hp_addr >>
7888c2ecf20Sopenharmony_ci					      HAL_ADDR_MSB_REG_SHIFT;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	cmd->ring_tail_off32_remote_addr_lo = tp_addr & HAL_ADDR_LSB_REG_MASK;
7918c2ecf20Sopenharmony_ci	cmd->ring_tail_off32_remote_addr_hi = (u64)tp_addr >>
7928c2ecf20Sopenharmony_ci					      HAL_ADDR_MSB_REG_SHIFT;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	cmd->ring_msi_addr_lo = params.msi_addr & 0xffffffff;
7958c2ecf20Sopenharmony_ci	cmd->ring_msi_addr_hi = ((uint64_t)(params.msi_addr) >> 32) & 0xffffffff;
7968c2ecf20Sopenharmony_ci	cmd->msi_data = params.msi_data;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	cmd->intr_info = FIELD_PREP(
7998c2ecf20Sopenharmony_ci			HTT_SRNG_SETUP_CMD_INTR_INFO_BATCH_COUNTER_THRESH,
8008c2ecf20Sopenharmony_ci			params.intr_batch_cntr_thres_entries * ring_entry_sz);
8018c2ecf20Sopenharmony_ci	cmd->intr_info |= FIELD_PREP(
8028c2ecf20Sopenharmony_ci			HTT_SRNG_SETUP_CMD_INTR_INFO_INTR_TIMER_THRESH,
8038c2ecf20Sopenharmony_ci			params.intr_timer_thres_us >> 3);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	cmd->info2 = 0;
8068c2ecf20Sopenharmony_ci	if (params.flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) {
8078c2ecf20Sopenharmony_ci		cmd->info2 = FIELD_PREP(
8088c2ecf20Sopenharmony_ci				HTT_SRNG_SETUP_CMD_INFO2_INTR_LOW_THRESH,
8098c2ecf20Sopenharmony_ci				params.low_threshold);
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11k_DBG_HAL,
8138c2ecf20Sopenharmony_ci		   "%s msi_addr_lo:0x%x, msi_addr_hi:0x%x, msi_data:0x%x\n",
8148c2ecf20Sopenharmony_ci		   __func__, cmd->ring_msi_addr_lo, cmd->ring_msi_addr_hi,
8158c2ecf20Sopenharmony_ci		   cmd->msi_data);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11k_DBG_HAL,
8188c2ecf20Sopenharmony_ci		   "ring_id:%d, ring_type:%d, intr_info:0x%x, flags:0x%x\n",
8198c2ecf20Sopenharmony_ci		   ring_id, ring_type, cmd->intr_info, cmd->info2);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);
8228c2ecf20Sopenharmony_ci	if (ret)
8238c2ecf20Sopenharmony_ci		goto err_free;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	return 0;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cierr_free:
8288c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	return ret;
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci#define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ)
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ciint ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
8388c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8398c2ecf20Sopenharmony_ci	struct htt_ver_req_cmd *cmd;
8408c2ecf20Sopenharmony_ci	int len = sizeof(*cmd);
8418c2ecf20Sopenharmony_ci	int ret;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	init_completion(&dp->htt_tgt_version_received);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	skb = ath11k_htc_alloc_skb(ab, len);
8468c2ecf20Sopenharmony_ci	if (!skb)
8478c2ecf20Sopenharmony_ci		return -ENOMEM;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	skb_put(skb, len);
8508c2ecf20Sopenharmony_ci	cmd = (struct htt_ver_req_cmd *)skb->data;
8518c2ecf20Sopenharmony_ci	cmd->ver_reg_info = FIELD_PREP(HTT_VER_REQ_INFO_MSG_ID,
8528c2ecf20Sopenharmony_ci				       HTT_H2T_MSG_TYPE_VERSION_REQ);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	ret = ath11k_htc_send(&ab->htc, dp->eid, skb);
8558c2ecf20Sopenharmony_ci	if (ret) {
8568c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
8578c2ecf20Sopenharmony_ci		return ret;
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	ret = wait_for_completion_timeout(&dp->htt_tgt_version_received,
8618c2ecf20Sopenharmony_ci					  HTT_TARGET_VERSION_TIMEOUT_HZ);
8628c2ecf20Sopenharmony_ci	if (ret == 0) {
8638c2ecf20Sopenharmony_ci		ath11k_warn(ab, "htt target version request timed out\n");
8648c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) {
8688c2ecf20Sopenharmony_ci		ath11k_err(ab, "unsupported htt major version %d supported version is %d\n",
8698c2ecf20Sopenharmony_ci			   dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR);
8708c2ecf20Sopenharmony_ci		return -ENOTSUPP;
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	return 0;
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ciint ath11k_dp_tx_htt_h2t_ppdu_stats_req(struct ath11k *ar, u32 mask)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
8798c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
8808c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8818c2ecf20Sopenharmony_ci	struct htt_ppdu_stats_cfg_cmd *cmd;
8828c2ecf20Sopenharmony_ci	int len = sizeof(*cmd);
8838c2ecf20Sopenharmony_ci	u8 pdev_mask;
8848c2ecf20Sopenharmony_ci	int ret;
8858c2ecf20Sopenharmony_ci	int i;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
8888c2ecf20Sopenharmony_ci		skb = ath11k_htc_alloc_skb(ab, len);
8898c2ecf20Sopenharmony_ci		if (!skb)
8908c2ecf20Sopenharmony_ci			return -ENOMEM;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci		skb_put(skb, len);
8938c2ecf20Sopenharmony_ci		cmd = (struct htt_ppdu_stats_cfg_cmd *)skb->data;
8948c2ecf20Sopenharmony_ci		cmd->msg = FIELD_PREP(HTT_PPDU_STATS_CFG_MSG_TYPE,
8958c2ecf20Sopenharmony_ci				      HTT_H2T_MSG_TYPE_PPDU_STATS_CFG);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci		pdev_mask = 1 << (ar->pdev_idx + i);
8988c2ecf20Sopenharmony_ci		cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_PDEV_ID, pdev_mask);
8998c2ecf20Sopenharmony_ci		cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK, mask);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		ret = ath11k_htc_send(&ab->htc, dp->eid, skb);
9028c2ecf20Sopenharmony_ci		if (ret) {
9038c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
9048c2ecf20Sopenharmony_ci			return ret;
9058c2ecf20Sopenharmony_ci		}
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	return 0;
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ciint ath11k_dp_tx_htt_rx_filter_setup(struct ath11k_base *ab, u32 ring_id,
9128c2ecf20Sopenharmony_ci				     int mac_id, enum hal_ring_type ring_type,
9138c2ecf20Sopenharmony_ci				     int rx_buf_size,
9148c2ecf20Sopenharmony_ci				     struct htt_rx_ring_tlv_filter *tlv_filter)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	struct htt_rx_ring_selection_cfg_cmd *cmd;
9178c2ecf20Sopenharmony_ci	struct hal_srng *srng = &ab->hal.srng_list[ring_id];
9188c2ecf20Sopenharmony_ci	struct hal_srng_params params;
9198c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9208c2ecf20Sopenharmony_ci	int len = sizeof(*cmd);
9218c2ecf20Sopenharmony_ci	enum htt_srng_ring_type htt_ring_type;
9228c2ecf20Sopenharmony_ci	enum htt_srng_ring_id htt_ring_id;
9238c2ecf20Sopenharmony_ci	int ret;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	skb = ath11k_htc_alloc_skb(ab, len);
9268c2ecf20Sopenharmony_ci	if (!skb)
9278c2ecf20Sopenharmony_ci		return -ENOMEM;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(params));
9308c2ecf20Sopenharmony_ci	ath11k_hal_srng_get_params(ab, srng, &params);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id,
9338c2ecf20Sopenharmony_ci					    ring_type, &htt_ring_type,
9348c2ecf20Sopenharmony_ci					    &htt_ring_id);
9358c2ecf20Sopenharmony_ci	if (ret)
9368c2ecf20Sopenharmony_ci		goto err_free;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	skb_put(skb, len);
9398c2ecf20Sopenharmony_ci	cmd = (struct htt_rx_ring_selection_cfg_cmd *)skb->data;
9408c2ecf20Sopenharmony_ci	cmd->info0 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_MSG_TYPE,
9418c2ecf20Sopenharmony_ci				HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG);
9428c2ecf20Sopenharmony_ci	if (htt_ring_type == HTT_SW_TO_HW_RING ||
9438c2ecf20Sopenharmony_ci	    htt_ring_type == HTT_HW_TO_SW_RING)
9448c2ecf20Sopenharmony_ci		cmd->info0 |=
9458c2ecf20Sopenharmony_ci			FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID,
9468c2ecf20Sopenharmony_ci				   DP_SW2HW_MACID(mac_id));
9478c2ecf20Sopenharmony_ci	else
9488c2ecf20Sopenharmony_ci		cmd->info0 |=
9498c2ecf20Sopenharmony_ci			FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID,
9508c2ecf20Sopenharmony_ci				   mac_id);
9518c2ecf20Sopenharmony_ci	cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_RING_ID,
9528c2ecf20Sopenharmony_ci				 htt_ring_id);
9538c2ecf20Sopenharmony_ci	cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_SS,
9548c2ecf20Sopenharmony_ci				 !!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP));
9558c2ecf20Sopenharmony_ci	cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS,
9568c2ecf20Sopenharmony_ci				 !!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP));
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	cmd->info1 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE,
9598c2ecf20Sopenharmony_ci				rx_buf_size);
9608c2ecf20Sopenharmony_ci	cmd->pkt_type_en_flags0 = tlv_filter->pkt_filter_flags0;
9618c2ecf20Sopenharmony_ci	cmd->pkt_type_en_flags1 = tlv_filter->pkt_filter_flags1;
9628c2ecf20Sopenharmony_ci	cmd->pkt_type_en_flags2 = tlv_filter->pkt_filter_flags2;
9638c2ecf20Sopenharmony_ci	cmd->pkt_type_en_flags3 = tlv_filter->pkt_filter_flags3;
9648c2ecf20Sopenharmony_ci	cmd->rx_filter_tlv = tlv_filter->rx_filter;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);
9678c2ecf20Sopenharmony_ci	if (ret)
9688c2ecf20Sopenharmony_ci		goto err_free;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	return 0;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_cierr_free:
9738c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	return ret;
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ciint
9798c2ecf20Sopenharmony_ciath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type,
9808c2ecf20Sopenharmony_ci				   struct htt_ext_stats_cfg_params *cfg_params,
9818c2ecf20Sopenharmony_ci				   u64 cookie)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
9848c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
9858c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9868c2ecf20Sopenharmony_ci	struct htt_ext_stats_cfg_cmd *cmd;
9878c2ecf20Sopenharmony_ci	int len = sizeof(*cmd);
9888c2ecf20Sopenharmony_ci	int ret;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	skb = ath11k_htc_alloc_skb(ab, len);
9918c2ecf20Sopenharmony_ci	if (!skb)
9928c2ecf20Sopenharmony_ci		return -ENOMEM;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	skb_put(skb, len);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	cmd = (struct htt_ext_stats_cfg_cmd *)skb->data;
9978c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
9988c2ecf20Sopenharmony_ci	cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	cmd->hdr.stats_type = type;
10038c2ecf20Sopenharmony_ci	cmd->cfg_param0 = cfg_params->cfg0;
10048c2ecf20Sopenharmony_ci	cmd->cfg_param1 = cfg_params->cfg1;
10058c2ecf20Sopenharmony_ci	cmd->cfg_param2 = cfg_params->cfg2;
10068c2ecf20Sopenharmony_ci	cmd->cfg_param3 = cfg_params->cfg3;
10078c2ecf20Sopenharmony_ci	cmd->cookie_lsb = lower_32_bits(cookie);
10088c2ecf20Sopenharmony_ci	cmd->cookie_msb = upper_32_bits(cookie);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	ret = ath11k_htc_send(&ab->htc, dp->eid, skb);
10118c2ecf20Sopenharmony_ci	if (ret) {
10128c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to send htt type stats request: %d",
10138c2ecf20Sopenharmony_ci			    ret);
10148c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
10158c2ecf20Sopenharmony_ci		return ret;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	return 0;
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ciint ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
10248c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
10258c2ecf20Sopenharmony_ci	struct htt_rx_ring_tlv_filter tlv_filter = {0};
10268c2ecf20Sopenharmony_ci	int ret = 0, ring_id = 0, i;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (!reset) {
10318c2ecf20Sopenharmony_ci		tlv_filter.rx_filter = HTT_RX_MON_FILTER_TLV_FLAGS_MON_BUF_RING;
10328c2ecf20Sopenharmony_ci		tlv_filter.pkt_filter_flags0 =
10338c2ecf20Sopenharmony_ci					HTT_RX_MON_FP_MGMT_FILTER_FLAGS0 |
10348c2ecf20Sopenharmony_ci					HTT_RX_MON_MO_MGMT_FILTER_FLAGS0;
10358c2ecf20Sopenharmony_ci		tlv_filter.pkt_filter_flags1 =
10368c2ecf20Sopenharmony_ci					HTT_RX_MON_FP_MGMT_FILTER_FLAGS1 |
10378c2ecf20Sopenharmony_ci					HTT_RX_MON_MO_MGMT_FILTER_FLAGS1;
10388c2ecf20Sopenharmony_ci		tlv_filter.pkt_filter_flags2 =
10398c2ecf20Sopenharmony_ci					HTT_RX_MON_FP_CTRL_FILTER_FLASG2 |
10408c2ecf20Sopenharmony_ci					HTT_RX_MON_MO_CTRL_FILTER_FLASG2;
10418c2ecf20Sopenharmony_ci		tlv_filter.pkt_filter_flags3 =
10428c2ecf20Sopenharmony_ci					HTT_RX_MON_FP_CTRL_FILTER_FLASG3 |
10438c2ecf20Sopenharmony_ci					HTT_RX_MON_MO_CTRL_FILTER_FLASG3 |
10448c2ecf20Sopenharmony_ci					HTT_RX_MON_FP_DATA_FILTER_FLASG3 |
10458c2ecf20Sopenharmony_ci					HTT_RX_MON_MO_DATA_FILTER_FLASG3;
10468c2ecf20Sopenharmony_ci	}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	if (ab->hw_params.rxdma1_enable) {
10498c2ecf20Sopenharmony_ci		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, dp->mac_id,
10508c2ecf20Sopenharmony_ci						       HAL_RXDMA_MONITOR_BUF,
10518c2ecf20Sopenharmony_ci						       DP_RXDMA_REFILL_RING_SIZE,
10528c2ecf20Sopenharmony_ci						       &tlv_filter);
10538c2ecf20Sopenharmony_ci	} else if (!reset) {
10548c2ecf20Sopenharmony_ci		/* set in monitor mode only */
10558c2ecf20Sopenharmony_ci		for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
10568c2ecf20Sopenharmony_ci			ring_id = dp->rx_mac_buf_ring[i].ring_id;
10578c2ecf20Sopenharmony_ci			ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id,
10588c2ecf20Sopenharmony_ci							       dp->mac_id + i,
10598c2ecf20Sopenharmony_ci							       HAL_RXDMA_BUF,
10608c2ecf20Sopenharmony_ci							       1024,
10618c2ecf20Sopenharmony_ci							       &tlv_filter);
10628c2ecf20Sopenharmony_ci		}
10638c2ecf20Sopenharmony_ci	}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	if (ret)
10668c2ecf20Sopenharmony_ci		return ret;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
10698c2ecf20Sopenharmony_ci		ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
10708c2ecf20Sopenharmony_ci		if (!reset)
10718c2ecf20Sopenharmony_ci			tlv_filter.rx_filter =
10728c2ecf20Sopenharmony_ci					HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING;
10738c2ecf20Sopenharmony_ci		else
10748c2ecf20Sopenharmony_ci			tlv_filter = ath11k_mac_mon_status_filter_default;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci		ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,
10778c2ecf20Sopenharmony_ci						       dp->mac_id + i,
10788c2ecf20Sopenharmony_ci						       HAL_RXDMA_MONITOR_STATUS,
10798c2ecf20Sopenharmony_ci						       DP_RXDMA_REFILL_RING_SIZE,
10808c2ecf20Sopenharmony_ci						       &tlv_filter);
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	if (!ar->ab->hw_params.rxdma1_enable)
10848c2ecf20Sopenharmony_ci		mod_timer(&ar->ab->mon_reap_timer, jiffies +
10858c2ecf20Sopenharmony_ci			  msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	return ret;
10888c2ecf20Sopenharmony_ci}
1089