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 <linux/ieee80211.h>
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
98c2ecf20Sopenharmony_ci#include <crypto/hash.h>
108c2ecf20Sopenharmony_ci#include "core.h"
118c2ecf20Sopenharmony_ci#include "debug.h"
128c2ecf20Sopenharmony_ci#include "debugfs_htt_stats.h"
138c2ecf20Sopenharmony_ci#include "debugfs_sta.h"
148c2ecf20Sopenharmony_ci#include "hal_desc.h"
158c2ecf20Sopenharmony_ci#include "hw.h"
168c2ecf20Sopenharmony_ci#include "dp_rx.h"
178c2ecf20Sopenharmony_ci#include "hal_rx.h"
188c2ecf20Sopenharmony_ci#include "dp_tx.h"
198c2ecf20Sopenharmony_ci#include "peer.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic u8 *ath11k_dp_rx_h_80211_hdr(struct hal_rx_desc *desc)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	return desc->hdr_status;
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct hal_rx_desc *desc)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	if (!(__le32_to_cpu(desc->mpdu_start.info1) &
318c2ecf20Sopenharmony_ci	    RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID))
328c2ecf20Sopenharmony_ci		return HAL_ENCRYPT_TYPE_OPEN;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MPDU_START_INFO2_ENC_TYPE,
358c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->mpdu_start.info2));
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_decap_type(struct hal_rx_desc *desc)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
418c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_start.info2));
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct hal_rx_desc *desc)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO2_MESH_CTRL_PRESENT,
478c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_start.info2));
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct hal_rx_desc *desc)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID,
538c2ecf20Sopenharmony_ci			   __le32_to_cpu(desc->mpdu_start.info1));
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct hal_rx_desc *desc)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_FCTRL_VALID,
598c2ecf20Sopenharmony_ci			   __le32_to_cpu(desc->mpdu_start.info1));
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_mpdu_start_more_frags(struct sk_buff *skb)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
678c2ecf20Sopenharmony_ci	return ieee80211_has_morefrags(hdr->frame_control);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct sk_buff *skb)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
758c2ecf20Sopenharmony_ci	return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct hal_rx_desc *desc)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_NUM,
818c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->mpdu_start.info1));
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_msdu_done(struct hal_rx_desc *desc)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE,
878c2ecf20Sopenharmony_ci			   __le32_to_cpu(desc->attention.info2));
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct hal_rx_desc *desc)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL,
938c2ecf20Sopenharmony_ci			   __le32_to_cpu(desc->attention.info1));
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct hal_rx_desc *desc)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL,
998c2ecf20Sopenharmony_ci			   __le32_to_cpu(desc->attention.info1));
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_attn_is_decrypted(struct hal_rx_desc *desc)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE,
1058c2ecf20Sopenharmony_ci			  __le32_to_cpu(desc->attention.info2)) ==
1068c2ecf20Sopenharmony_ci		RX_DESC_DECRYPT_STATUS_CODE_OK);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rx_h_attn_mpdu_err(struct hal_rx_desc *desc)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	u32 info = __le32_to_cpu(desc->attention.info1);
1128c2ecf20Sopenharmony_ci	u32 errmap = 0;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (info & RX_ATTENTION_INFO1_FCS_ERR)
1158c2ecf20Sopenharmony_ci		errmap |= DP_RX_MPDU_ERR_FCS;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (info & RX_ATTENTION_INFO1_DECRYPT_ERR)
1188c2ecf20Sopenharmony_ci		errmap |= DP_RX_MPDU_ERR_DECRYPT;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (info & RX_ATTENTION_INFO1_TKIP_MIC_ERR)
1218c2ecf20Sopenharmony_ci		errmap |= DP_RX_MPDU_ERR_TKIP_MIC;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (info & RX_ATTENTION_INFO1_A_MSDU_ERROR)
1248c2ecf20Sopenharmony_ci		errmap |= DP_RX_MPDU_ERR_AMSDU_ERR;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (info & RX_ATTENTION_INFO1_OVERFLOW_ERR)
1278c2ecf20Sopenharmony_ci		errmap |= DP_RX_MPDU_ERR_OVERFLOW;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (info & RX_ATTENTION_INFO1_MSDU_LEN_ERR)
1308c2ecf20Sopenharmony_ci		errmap |= DP_RX_MPDU_ERR_MSDU_LEN;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (info & RX_ATTENTION_INFO1_MPDU_LEN_ERR)
1338c2ecf20Sopenharmony_ci		errmap |= DP_RX_MPDU_ERR_MPDU_LEN;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return errmap;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct hal_rx_desc *desc)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH,
1418c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_start.info1));
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_sgi(struct hal_rx_desc *desc)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO3_SGI,
1478c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_start.info3));
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct hal_rx_desc *desc)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS,
1538c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_start.info3));
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct hal_rx_desc *desc)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW,
1598c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_start.info3));
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rx_h_msdu_start_freq(struct hal_rx_desc *desc)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return __le32_to_cpu(desc->msdu_start.phy_meta_data);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct hal_rx_desc *desc)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE,
1708c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_start.info3));
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_start_nss(struct hal_rx_desc *desc)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	u8 mimo_ss_bitmap = FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP,
1768c2ecf20Sopenharmony_ci				      __le32_to_cpu(desc->msdu_start.info3));
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return hweight8(mimo_ss_bitmap);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_mpdu_start_tid(struct hal_rx_desc *desc)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MPDU_START_INFO2_TID,
1848c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->mpdu_start.info2));
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct hal_rx_desc *desc)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	return __le16_to_cpu(desc->mpdu_start.sw_peer_id);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic u8 ath11k_dp_rx_h_msdu_end_l3pad(struct hal_rx_desc *desc)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_END_INFO2_L3_HDR_PADDING,
1958c2ecf20Sopenharmony_ci			 __le32_to_cpu(desc->msdu_end.info2));
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_msdu_end_first_msdu(struct hal_rx_desc *desc)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU,
2018c2ecf20Sopenharmony_ci			   __le32_to_cpu(desc->msdu_end.info2));
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_msdu_end_last_msdu(struct hal_rx_desc *desc)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	return !!FIELD_GET(RX_MSDU_END_INFO2_LAST_MSDU,
2078c2ecf20Sopenharmony_ci			   __le32_to_cpu(desc->msdu_end.info2));
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_desc_end_tlv_copy(struct hal_rx_desc *fdesc,
2118c2ecf20Sopenharmony_ci					   struct hal_rx_desc *ldesc)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	memcpy((u8 *)&fdesc->msdu_end, (u8 *)&ldesc->msdu_end,
2148c2ecf20Sopenharmony_ci	       sizeof(struct rx_msdu_end));
2158c2ecf20Sopenharmony_ci	memcpy((u8 *)&fdesc->attention, (u8 *)&ldesc->attention,
2168c2ecf20Sopenharmony_ci	       sizeof(struct rx_attention));
2178c2ecf20Sopenharmony_ci	memcpy((u8 *)&fdesc->mpdu_end, (u8 *)&ldesc->mpdu_end,
2188c2ecf20Sopenharmony_ci	       sizeof(struct rx_mpdu_end));
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rxdesc_get_mpdulen_err(struct hal_rx_desc *rx_desc)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct rx_attention *rx_attn;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	rx_attn = &rx_desc->attention;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR,
2288c2ecf20Sopenharmony_ci			 __le32_to_cpu(rx_attn->info1));
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rxdesc_get_decap_format(struct hal_rx_desc *rx_desc)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct rx_msdu_start *rx_msdu_start;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	rx_msdu_start = &rx_desc->msdu_start;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
2388c2ecf20Sopenharmony_ci			 __le32_to_cpu(rx_msdu_start->info2));
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic u8 *ath11k_dp_rxdesc_get_80211hdr(struct hal_rx_desc *rx_desc)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	u8 *rx_pkt_hdr;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	rx_pkt_hdr = &rx_desc->msdu_payload[0];
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return rx_pkt_hdr;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic bool ath11k_dp_rxdesc_mpdu_valid(struct hal_rx_desc *rx_desc)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	u32 tlv_tag;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	tlv_tag = FIELD_GET(HAL_TLV_HDR_TAG,
2558c2ecf20Sopenharmony_ci			    __le32_to_cpu(rx_desc->mpdu_start_tag));
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return tlv_tag == HAL_RX_MPDU_START;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rxdesc_get_ppduid(struct hal_rx_desc *rx_desc)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	return __le16_to_cpu(rx_desc->mpdu_start.phy_ppdu_id);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic void ath11k_dp_service_mon_ring(struct timer_list *t)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer);
2688c2ecf20Sopenharmony_ci	int i;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++)
2718c2ecf20Sopenharmony_ci		ath11k_dp_rx_process_mon_rings(ab, i, NULL, DP_MON_SERVICE_BUDGET);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	mod_timer(&ab->mon_reap_timer, jiffies +
2748c2ecf20Sopenharmony_ci		  msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci/* Returns number of Rx buffers replenished */
2788c2ecf20Sopenharmony_ciint ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id,
2798c2ecf20Sopenharmony_ci			       struct dp_rxdma_ring *rx_ring,
2808c2ecf20Sopenharmony_ci			       int req_entries,
2818c2ecf20Sopenharmony_ci			       enum hal_rx_buf_return_buf_manager mgr)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct hal_srng *srng;
2848c2ecf20Sopenharmony_ci	u32 *desc;
2858c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2868c2ecf20Sopenharmony_ci	int num_free;
2878c2ecf20Sopenharmony_ci	int num_remain;
2888c2ecf20Sopenharmony_ci	int buf_id;
2898c2ecf20Sopenharmony_ci	u32 cookie;
2908c2ecf20Sopenharmony_ci	dma_addr_t paddr;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	req_entries = min(req_entries, rx_ring->bufs_max);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	num_free = ath11k_hal_srng_src_num_free(ab, srng, true);
3018c2ecf20Sopenharmony_ci	if (!req_entries && (num_free > (rx_ring->bufs_max * 3) / 4))
3028c2ecf20Sopenharmony_ci		req_entries = num_free;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	req_entries = min(num_free, req_entries);
3058c2ecf20Sopenharmony_ci	num_remain = req_entries;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	while (num_remain > 0) {
3088c2ecf20Sopenharmony_ci		skb = dev_alloc_skb(DP_RX_BUFFER_SIZE +
3098c2ecf20Sopenharmony_ci				    DP_RX_BUFFER_ALIGN_SIZE);
3108c2ecf20Sopenharmony_ci		if (!skb)
3118c2ecf20Sopenharmony_ci			break;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		if (!IS_ALIGNED((unsigned long)skb->data,
3148c2ecf20Sopenharmony_ci				DP_RX_BUFFER_ALIGN_SIZE)) {
3158c2ecf20Sopenharmony_ci			skb_pull(skb,
3168c2ecf20Sopenharmony_ci				 PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) -
3178c2ecf20Sopenharmony_ci				 skb->data);
3188c2ecf20Sopenharmony_ci		}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci		paddr = dma_map_single(ab->dev, skb->data,
3218c2ecf20Sopenharmony_ci				       skb->len + skb_tailroom(skb),
3228c2ecf20Sopenharmony_ci				       DMA_FROM_DEVICE);
3238c2ecf20Sopenharmony_ci		if (dma_mapping_error(ab->dev, paddr))
3248c2ecf20Sopenharmony_ci			goto fail_free_skb;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		spin_lock_bh(&rx_ring->idr_lock);
3278c2ecf20Sopenharmony_ci		buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 1,
3288c2ecf20Sopenharmony_ci				   (rx_ring->bufs_max * 3) + 1, GFP_ATOMIC);
3298c2ecf20Sopenharmony_ci		spin_unlock_bh(&rx_ring->idr_lock);
3308c2ecf20Sopenharmony_ci		if (buf_id <= 0)
3318c2ecf20Sopenharmony_ci			goto fail_dma_unmap;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
3348c2ecf20Sopenharmony_ci		if (!desc)
3358c2ecf20Sopenharmony_ci			goto fail_idr_remove;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		ATH11K_SKB_RXCB(skb)->paddr = paddr;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) |
3408c2ecf20Sopenharmony_ci			 FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		num_remain--;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr);
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return req_entries - num_remain;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cifail_idr_remove:
3548c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_ring->idr_lock);
3558c2ecf20Sopenharmony_ci	idr_remove(&rx_ring->bufs_idr, buf_id);
3568c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_ring->idr_lock);
3578c2ecf20Sopenharmony_cifail_dma_unmap:
3588c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
3598c2ecf20Sopenharmony_ci			 DMA_FROM_DEVICE);
3608c2ecf20Sopenharmony_cifail_free_skb:
3618c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	return req_entries - num_remain;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar,
3718c2ecf20Sopenharmony_ci					 struct dp_rxdma_ring *rx_ring)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
3748c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3758c2ecf20Sopenharmony_ci	int buf_id;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_ring->idr_lock);
3788c2ecf20Sopenharmony_ci	idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) {
3798c2ecf20Sopenharmony_ci		idr_remove(&rx_ring->bufs_idr, buf_id);
3808c2ecf20Sopenharmony_ci		/* TODO: Understand where internal driver does this dma_unmap of
3818c2ecf20Sopenharmony_ci		 * of rxdma_buffer.
3828c2ecf20Sopenharmony_ci		 */
3838c2ecf20Sopenharmony_ci		dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
3848c2ecf20Sopenharmony_ci				 skb->len + skb_tailroom(skb), DMA_FROM_DEVICE);
3858c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	idr_destroy(&rx_ring->bufs_idr);
3898c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_ring->idr_lock);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* if rxdma1_enable is false, mon_status_refill_ring
3928c2ecf20Sopenharmony_ci	 * isn't setup, so don't clean.
3938c2ecf20Sopenharmony_ci	 */
3948c2ecf20Sopenharmony_ci	if (!ar->ab->hw_params.rxdma1_enable)
3958c2ecf20Sopenharmony_ci		return 0;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	rx_ring = &dp->rx_mon_status_refill_ring[0];
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_ring->idr_lock);
4008c2ecf20Sopenharmony_ci	idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) {
4018c2ecf20Sopenharmony_ci		idr_remove(&rx_ring->bufs_idr, buf_id);
4028c2ecf20Sopenharmony_ci		/* XXX: Understand where internal driver does this dma_unmap of
4038c2ecf20Sopenharmony_ci		 * of rxdma_buffer.
4048c2ecf20Sopenharmony_ci		 */
4058c2ecf20Sopenharmony_ci		dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
4068c2ecf20Sopenharmony_ci				 skb->len + skb_tailroom(skb), DMA_BIDIRECTIONAL);
4078c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	idr_destroy(&rx_ring->bufs_idr);
4118c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_ring->idr_lock);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return 0;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_pdev_buf_free(struct ath11k *ar)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
4198c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
4208c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
4218c2ecf20Sopenharmony_ci	int i;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	ath11k_dp_rxdma_buf_ring_free(ar, rx_ring);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	rx_ring = &dp->rxdma_mon_buf_ring;
4268c2ecf20Sopenharmony_ci	ath11k_dp_rxdma_buf_ring_free(ar, rx_ring);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
4298c2ecf20Sopenharmony_ci		rx_ring = &dp->rx_mon_status_refill_ring[i];
4308c2ecf20Sopenharmony_ci		ath11k_dp_rxdma_buf_ring_free(ar, rx_ring);
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar,
4378c2ecf20Sopenharmony_ci					  struct dp_rxdma_ring *rx_ring,
4388c2ecf20Sopenharmony_ci					  u32 ringtype)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
4418c2ecf20Sopenharmony_ci	int num_entries;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	num_entries = rx_ring->refill_buf_ring.size /
4448c2ecf20Sopenharmony_ci		ath11k_hal_srng_get_entrysize(ar->ab, ringtype);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	rx_ring->bufs_max = num_entries;
4478c2ecf20Sopenharmony_ci	ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries,
4488c2ecf20Sopenharmony_ci				   HAL_RX_BUF_RBM_SW3_BM);
4498c2ecf20Sopenharmony_ci	return 0;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
4558c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
4568c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
4578c2ecf20Sopenharmony_ci	int i;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_BUF);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	if (ar->ab->hw_params.rxdma1_enable) {
4628c2ecf20Sopenharmony_ci		rx_ring = &dp->rxdma_mon_buf_ring;
4638c2ecf20Sopenharmony_ci		ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF);
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
4678c2ecf20Sopenharmony_ci		rx_ring = &dp->rx_mon_status_refill_ring[i];
4688c2ecf20Sopenharmony_ci		ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS);
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_pdev_srng_free(struct ath11k *ar)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
4778c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
4788c2ecf20Sopenharmony_ci	int i;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	ath11k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
4838c2ecf20Sopenharmony_ci		if (ab->hw_params.rx_mac_buf_ring)
4848c2ecf20Sopenharmony_ci			ath11k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		ath11k_dp_srng_cleanup(ab, &dp->rxdma_err_dst_ring[i]);
4878c2ecf20Sopenharmony_ci		ath11k_dp_srng_cleanup(ab,
4888c2ecf20Sopenharmony_ci				       &dp->rx_mon_status_refill_ring[i].refill_buf_ring);
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	ath11k_dp_srng_cleanup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring);
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_civoid ath11k_dp_pdev_reo_cleanup(struct ath11k_base *ab)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
4978c2ecf20Sopenharmony_ci	int i;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	for (i = 0; i < DP_REO_DST_RING_MAX; i++)
5008c2ecf20Sopenharmony_ci		ath11k_dp_srng_cleanup(ab, &dp->reo_dst_ring[i]);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ciint ath11k_dp_pdev_reo_setup(struct ath11k_base *ab)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
5068c2ecf20Sopenharmony_ci	int ret;
5078c2ecf20Sopenharmony_ci	int i;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for (i = 0; i < DP_REO_DST_RING_MAX; i++) {
5108c2ecf20Sopenharmony_ci		ret = ath11k_dp_srng_setup(ab, &dp->reo_dst_ring[i],
5118c2ecf20Sopenharmony_ci					   HAL_REO_DST, i, 0,
5128c2ecf20Sopenharmony_ci					   DP_REO_DST_RING_SIZE);
5138c2ecf20Sopenharmony_ci		if (ret) {
5148c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to setup reo_dst_ring\n");
5158c2ecf20Sopenharmony_ci			goto err_reo_cleanup;
5168c2ecf20Sopenharmony_ci		}
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cierr_reo_cleanup:
5228c2ecf20Sopenharmony_ci	ath11k_dp_pdev_reo_cleanup(ab);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return ret;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
5308c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
5318c2ecf20Sopenharmony_ci	struct dp_srng *srng = NULL;
5328c2ecf20Sopenharmony_ci	int i;
5338c2ecf20Sopenharmony_ci	int ret;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	ret = ath11k_dp_srng_setup(ar->ab,
5368c2ecf20Sopenharmony_ci				   &dp->rx_refill_buf_ring.refill_buf_ring,
5378c2ecf20Sopenharmony_ci				   HAL_RXDMA_BUF, 0,
5388c2ecf20Sopenharmony_ci				   dp->mac_id, DP_RXDMA_BUF_RING_SIZE);
5398c2ecf20Sopenharmony_ci	if (ret) {
5408c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to setup rx_refill_buf_ring\n");
5418c2ecf20Sopenharmony_ci		return ret;
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	if (ar->ab->hw_params.rx_mac_buf_ring) {
5458c2ecf20Sopenharmony_ci		for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
5468c2ecf20Sopenharmony_ci			ret = ath11k_dp_srng_setup(ar->ab,
5478c2ecf20Sopenharmony_ci						   &dp->rx_mac_buf_ring[i],
5488c2ecf20Sopenharmony_ci						   HAL_RXDMA_BUF, 1,
5498c2ecf20Sopenharmony_ci						   dp->mac_id + i, 1024);
5508c2ecf20Sopenharmony_ci			if (ret) {
5518c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to setup rx_mac_buf_ring %d\n",
5528c2ecf20Sopenharmony_ci					    i);
5538c2ecf20Sopenharmony_ci				return ret;
5548c2ecf20Sopenharmony_ci			}
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
5598c2ecf20Sopenharmony_ci		ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring[i],
5608c2ecf20Sopenharmony_ci					   HAL_RXDMA_DST, 0, dp->mac_id + i,
5618c2ecf20Sopenharmony_ci					   DP_RXDMA_ERR_DST_RING_SIZE);
5628c2ecf20Sopenharmony_ci		if (ret) {
5638c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring %d\n", i);
5648c2ecf20Sopenharmony_ci			return ret;
5658c2ecf20Sopenharmony_ci		}
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
5698c2ecf20Sopenharmony_ci		srng = &dp->rx_mon_status_refill_ring[i].refill_buf_ring;
5708c2ecf20Sopenharmony_ci		ret = ath11k_dp_srng_setup(ar->ab,
5718c2ecf20Sopenharmony_ci					   srng,
5728c2ecf20Sopenharmony_ci					   HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id + i,
5738c2ecf20Sopenharmony_ci					   DP_RXDMA_MON_STATUS_RING_SIZE);
5748c2ecf20Sopenharmony_ci		if (ret) {
5758c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
5768c2ecf20Sopenharmony_ci				    "failed to setup rx_mon_status_refill_ring %d\n", i);
5778c2ecf20Sopenharmony_ci			return ret;
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* if rxdma1_enable is false, then it doesn't need
5828c2ecf20Sopenharmony_ci	 * to setup rxdam_mon_buf_ring, rxdma_mon_dst_ring
5838c2ecf20Sopenharmony_ci	 * and rxdma_mon_desc_ring.
5848c2ecf20Sopenharmony_ci	 * init reap timer for QCA6390.
5858c2ecf20Sopenharmony_ci	 */
5868c2ecf20Sopenharmony_ci	if (!ar->ab->hw_params.rxdma1_enable) {
5878c2ecf20Sopenharmony_ci		//init mon status buffer reap timer
5888c2ecf20Sopenharmony_ci		timer_setup(&ar->ab->mon_reap_timer,
5898c2ecf20Sopenharmony_ci			    ath11k_dp_service_mon_ring, 0);
5908c2ecf20Sopenharmony_ci		return 0;
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	ret = ath11k_dp_srng_setup(ar->ab,
5948c2ecf20Sopenharmony_ci				   &dp->rxdma_mon_buf_ring.refill_buf_ring,
5958c2ecf20Sopenharmony_ci				   HAL_RXDMA_MONITOR_BUF, 0, dp->mac_id,
5968c2ecf20Sopenharmony_ci				   DP_RXDMA_MONITOR_BUF_RING_SIZE);
5978c2ecf20Sopenharmony_ci	if (ret) {
5988c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
5998c2ecf20Sopenharmony_ci			    "failed to setup HAL_RXDMA_MONITOR_BUF\n");
6008c2ecf20Sopenharmony_ci		return ret;
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_dst_ring,
6048c2ecf20Sopenharmony_ci				   HAL_RXDMA_MONITOR_DST, 0, dp->mac_id,
6058c2ecf20Sopenharmony_ci				   DP_RXDMA_MONITOR_DST_RING_SIZE);
6068c2ecf20Sopenharmony_ci	if (ret) {
6078c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
6088c2ecf20Sopenharmony_ci			    "failed to setup HAL_RXDMA_MONITOR_DST\n");
6098c2ecf20Sopenharmony_ci		return ret;
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_desc_ring,
6138c2ecf20Sopenharmony_ci				   HAL_RXDMA_MONITOR_DESC, 0, dp->mac_id,
6148c2ecf20Sopenharmony_ci				   DP_RXDMA_MONITOR_DESC_RING_SIZE);
6158c2ecf20Sopenharmony_ci	if (ret) {
6168c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
6178c2ecf20Sopenharmony_ci			    "failed to setup HAL_RXDMA_MONITOR_DESC\n");
6188c2ecf20Sopenharmony_ci		return ret;
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	return 0;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_civoid ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
6278c2ecf20Sopenharmony_ci	struct dp_reo_cmd *cmd, *tmp;
6288c2ecf20Sopenharmony_ci	struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	spin_lock_bh(&dp->reo_cmd_lock);
6318c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
6328c2ecf20Sopenharmony_ci		list_del(&cmd->list);
6338c2ecf20Sopenharmony_ci		dma_unmap_single(ab->dev, cmd->data.paddr,
6348c2ecf20Sopenharmony_ci				 cmd->data.size, DMA_BIDIRECTIONAL);
6358c2ecf20Sopenharmony_ci		kfree(cmd->data.vaddr);
6368c2ecf20Sopenharmony_ci		kfree(cmd);
6378c2ecf20Sopenharmony_ci	}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cmd_cache, tmp_cache,
6408c2ecf20Sopenharmony_ci				 &dp->reo_cmd_cache_flush_list, list) {
6418c2ecf20Sopenharmony_ci		list_del(&cmd_cache->list);
6428c2ecf20Sopenharmony_ci		dp->reo_cmd_cache_flush_count--;
6438c2ecf20Sopenharmony_ci		dma_unmap_single(ab->dev, cmd_cache->data.paddr,
6448c2ecf20Sopenharmony_ci				 cmd_cache->data.size, DMA_BIDIRECTIONAL);
6458c2ecf20Sopenharmony_ci		kfree(cmd_cache->data.vaddr);
6468c2ecf20Sopenharmony_ci		kfree(cmd_cache);
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci	spin_unlock_bh(&dp->reo_cmd_lock);
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx,
6528c2ecf20Sopenharmony_ci				   enum hal_reo_cmd_status status)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid = ctx;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (status != HAL_REO_CMD_SUCCESS)
6578c2ecf20Sopenharmony_ci		ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
6588c2ecf20Sopenharmony_ci			    rx_tid->tid, status);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
6618c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
6628c2ecf20Sopenharmony_ci	kfree(rx_tid->vaddr);
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
6668c2ecf20Sopenharmony_ci				      struct dp_rx_tid *rx_tid)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	struct ath11k_hal_reo_cmd cmd = {0};
6698c2ecf20Sopenharmony_ci	unsigned long tot_desc_sz, desc_sz;
6708c2ecf20Sopenharmony_ci	int ret;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	tot_desc_sz = rx_tid->size;
6738c2ecf20Sopenharmony_ci	desc_sz = ath11k_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	while (tot_desc_sz > desc_sz) {
6768c2ecf20Sopenharmony_ci		tot_desc_sz -= desc_sz;
6778c2ecf20Sopenharmony_ci		cmd.addr_lo = lower_32_bits(rx_tid->paddr + tot_desc_sz);
6788c2ecf20Sopenharmony_ci		cmd.addr_hi = upper_32_bits(rx_tid->paddr);
6798c2ecf20Sopenharmony_ci		ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid,
6808c2ecf20Sopenharmony_ci						HAL_REO_CMD_FLUSH_CACHE, &cmd,
6818c2ecf20Sopenharmony_ci						NULL);
6828c2ecf20Sopenharmony_ci		if (ret)
6838c2ecf20Sopenharmony_ci			ath11k_warn(ab,
6848c2ecf20Sopenharmony_ci				    "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n",
6858c2ecf20Sopenharmony_ci				    rx_tid->tid, ret);
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	memset(&cmd, 0, sizeof(cmd));
6898c2ecf20Sopenharmony_ci	cmd.addr_lo = lower_32_bits(rx_tid->paddr);
6908c2ecf20Sopenharmony_ci	cmd.addr_hi = upper_32_bits(rx_tid->paddr);
6918c2ecf20Sopenharmony_ci	cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS;
6928c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid,
6938c2ecf20Sopenharmony_ci					HAL_REO_CMD_FLUSH_CACHE,
6948c2ecf20Sopenharmony_ci					&cmd, ath11k_dp_reo_cmd_free);
6958c2ecf20Sopenharmony_ci	if (ret) {
6968c2ecf20Sopenharmony_ci		ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
6978c2ecf20Sopenharmony_ci			   rx_tid->tid, ret);
6988c2ecf20Sopenharmony_ci		dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
6998c2ecf20Sopenharmony_ci				 DMA_BIDIRECTIONAL);
7008c2ecf20Sopenharmony_ci		kfree(rx_tid->vaddr);
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
7058c2ecf20Sopenharmony_ci				      enum hal_reo_cmd_status status)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	struct ath11k_base *ab = dp->ab;
7088c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid = ctx;
7098c2ecf20Sopenharmony_ci	struct dp_reo_cache_flush_elem *elem, *tmp;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (status == HAL_REO_CMD_DRAIN) {
7128c2ecf20Sopenharmony_ci		goto free_desc;
7138c2ecf20Sopenharmony_ci	} else if (status != HAL_REO_CMD_SUCCESS) {
7148c2ecf20Sopenharmony_ci		/* Shouldn't happen! Cleanup in case of other failure? */
7158c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to delete rx tid %d hw descriptor %d\n",
7168c2ecf20Sopenharmony_ci			    rx_tid->tid, status);
7178c2ecf20Sopenharmony_ci		return;
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	elem = kzalloc(sizeof(*elem), GFP_ATOMIC);
7218c2ecf20Sopenharmony_ci	if (!elem)
7228c2ecf20Sopenharmony_ci		goto free_desc;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	elem->ts = jiffies;
7258c2ecf20Sopenharmony_ci	memcpy(&elem->data, rx_tid, sizeof(*rx_tid));
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	spin_lock_bh(&dp->reo_cmd_lock);
7288c2ecf20Sopenharmony_ci	list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list);
7298c2ecf20Sopenharmony_ci	dp->reo_cmd_cache_flush_count++;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	/* Flush and invalidate aged REO desc from HW cache */
7328c2ecf20Sopenharmony_ci	list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list,
7338c2ecf20Sopenharmony_ci				 list) {
7348c2ecf20Sopenharmony_ci		if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD ||
7358c2ecf20Sopenharmony_ci		    time_after(jiffies, elem->ts +
7368c2ecf20Sopenharmony_ci			       msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) {
7378c2ecf20Sopenharmony_ci			list_del(&elem->list);
7388c2ecf20Sopenharmony_ci			dp->reo_cmd_cache_flush_count--;
7398c2ecf20Sopenharmony_ci			spin_unlock_bh(&dp->reo_cmd_lock);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci			ath11k_dp_reo_cache_flush(ab, &elem->data);
7428c2ecf20Sopenharmony_ci			kfree(elem);
7438c2ecf20Sopenharmony_ci			spin_lock_bh(&dp->reo_cmd_lock);
7448c2ecf20Sopenharmony_ci		}
7458c2ecf20Sopenharmony_ci	}
7468c2ecf20Sopenharmony_ci	spin_unlock_bh(&dp->reo_cmd_lock);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	return;
7498c2ecf20Sopenharmony_cifree_desc:
7508c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
7518c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
7528c2ecf20Sopenharmony_ci	kfree(rx_tid->vaddr);
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_civoid ath11k_peer_rx_tid_delete(struct ath11k *ar,
7568c2ecf20Sopenharmony_ci			       struct ath11k_peer *peer, u8 tid)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct ath11k_hal_reo_cmd cmd = {0};
7598c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid = &peer->rx_tid[tid];
7608c2ecf20Sopenharmony_ci	int ret;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	if (!rx_tid->active)
7638c2ecf20Sopenharmony_ci		return;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
7668c2ecf20Sopenharmony_ci	cmd.addr_lo = lower_32_bits(rx_tid->paddr);
7678c2ecf20Sopenharmony_ci	cmd.addr_hi = upper_32_bits(rx_tid->paddr);
7688c2ecf20Sopenharmony_ci	cmd.upd0 |= HAL_REO_CMD_UPD0_VLD;
7698c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid,
7708c2ecf20Sopenharmony_ci					HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd,
7718c2ecf20Sopenharmony_ci					ath11k_dp_rx_tid_del_func);
7728c2ecf20Sopenharmony_ci	if (ret) {
7738c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
7748c2ecf20Sopenharmony_ci			   tid, ret);
7758c2ecf20Sopenharmony_ci		dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
7768c2ecf20Sopenharmony_ci				 DMA_BIDIRECTIONAL);
7778c2ecf20Sopenharmony_ci		kfree(rx_tid->vaddr);
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	rx_tid->active = false;
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
7848c2ecf20Sopenharmony_ci					 u32 *link_desc,
7858c2ecf20Sopenharmony_ci					 enum hal_wbm_rel_bm_act action)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
7888c2ecf20Sopenharmony_ci	struct hal_srng *srng;
7898c2ecf20Sopenharmony_ci	u32 *desc;
7908c2ecf20Sopenharmony_ci	int ret = 0;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[dp->wbm_desc_rel_ring.ring_id];
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
7998c2ecf20Sopenharmony_ci	if (!desc) {
8008c2ecf20Sopenharmony_ci		ret = -ENOBUFS;
8018c2ecf20Sopenharmony_ci		goto exit;
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	ath11k_hal_rx_msdu_link_desc_set(ab, (void *)desc, (void *)link_desc,
8058c2ecf20Sopenharmony_ci					 action);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ciexit:
8088c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	return ret;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_frags_cleanup(struct dp_rx_tid *rx_tid, bool rel_link_desc)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	struct ath11k_base *ab = rx_tid->ab;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	lockdep_assert_held(&ab->base_lock);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (rx_tid->dst_ring_desc) {
8228c2ecf20Sopenharmony_ci		if (rel_link_desc)
8238c2ecf20Sopenharmony_ci			ath11k_dp_rx_link_desc_return(ab, (u32 *)rx_tid->dst_ring_desc,
8248c2ecf20Sopenharmony_ci						      HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
8258c2ecf20Sopenharmony_ci		kfree(rx_tid->dst_ring_desc);
8268c2ecf20Sopenharmony_ci		rx_tid->dst_ring_desc = NULL;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	rx_tid->cur_sn = 0;
8308c2ecf20Sopenharmony_ci	rx_tid->last_frag_no = 0;
8318c2ecf20Sopenharmony_ci	rx_tid->rx_frag_bitmap = 0;
8328c2ecf20Sopenharmony_ci	__skb_queue_purge(&rx_tid->rx_frags);
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_civoid ath11k_peer_frags_flush(struct ath11k *ar, struct ath11k_peer *peer)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid;
8388c2ecf20Sopenharmony_ci	int i;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->ab->base_lock);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	for (i = 0; i <= IEEE80211_NUM_TIDS; i++) {
8438c2ecf20Sopenharmony_ci		rx_tid = &peer->rx_tid[i];
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->ab->base_lock);
8468c2ecf20Sopenharmony_ci		del_timer_sync(&rx_tid->frag_timer);
8478c2ecf20Sopenharmony_ci		spin_lock_bh(&ar->ab->base_lock);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci		ath11k_dp_rx_frags_cleanup(rx_tid, true);
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_civoid ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid;
8568c2ecf20Sopenharmony_ci	int i;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->ab->base_lock);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	for (i = 0; i <= IEEE80211_NUM_TIDS; i++) {
8618c2ecf20Sopenharmony_ci		rx_tid = &peer->rx_tid[i];
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		ath11k_peer_rx_tid_delete(ar, peer, i);
8648c2ecf20Sopenharmony_ci		ath11k_dp_rx_frags_cleanup(rx_tid, true);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->ab->base_lock);
8678c2ecf20Sopenharmony_ci		del_timer_sync(&rx_tid->frag_timer);
8688c2ecf20Sopenharmony_ci		spin_lock_bh(&ar->ab->base_lock);
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_cistatic int ath11k_peer_rx_tid_reo_update(struct ath11k *ar,
8738c2ecf20Sopenharmony_ci					 struct ath11k_peer *peer,
8748c2ecf20Sopenharmony_ci					 struct dp_rx_tid *rx_tid,
8758c2ecf20Sopenharmony_ci					 u32 ba_win_sz, u16 ssn,
8768c2ecf20Sopenharmony_ci					 bool update_ssn)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct ath11k_hal_reo_cmd cmd = {0};
8798c2ecf20Sopenharmony_ci	int ret;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	cmd.addr_lo = lower_32_bits(rx_tid->paddr);
8828c2ecf20Sopenharmony_ci	cmd.addr_hi = upper_32_bits(rx_tid->paddr);
8838c2ecf20Sopenharmony_ci	cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
8848c2ecf20Sopenharmony_ci	cmd.upd0 = HAL_REO_CMD_UPD0_BA_WINDOW_SIZE;
8858c2ecf20Sopenharmony_ci	cmd.ba_window_size = ba_win_sz;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (update_ssn) {
8888c2ecf20Sopenharmony_ci		cmd.upd0 |= HAL_REO_CMD_UPD0_SSN;
8898c2ecf20Sopenharmony_ci		cmd.upd2 = FIELD_PREP(HAL_REO_CMD_UPD2_SSN, ssn);
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid,
8938c2ecf20Sopenharmony_ci					HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd,
8948c2ecf20Sopenharmony_ci					NULL);
8958c2ecf20Sopenharmony_ci	if (ret) {
8968c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to update rx tid queue, tid %d (%d)\n",
8978c2ecf20Sopenharmony_ci			    rx_tid->tid, ret);
8988c2ecf20Sopenharmony_ci		return ret;
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	rx_tid->ba_win_sz = ba_win_sz;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	return 0;
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab,
9078c2ecf20Sopenharmony_ci				      const u8 *peer_mac, int vdev_id, u8 tid)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
9108c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, vdev_id, peer_mac);
9158c2ecf20Sopenharmony_ci	if (!peer) {
9168c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to find the peer to free up rx tid mem\n");
9178c2ecf20Sopenharmony_ci		goto unlock_exit;
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	rx_tid = &peer->rx_tid[tid];
9218c2ecf20Sopenharmony_ci	if (!rx_tid->active)
9228c2ecf20Sopenharmony_ci		goto unlock_exit;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
9258c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
9268c2ecf20Sopenharmony_ci	kfree(rx_tid->vaddr);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	rx_tid->active = false;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ciunlock_exit:
9318c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ciint ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
9358c2ecf20Sopenharmony_ci			     u8 tid, u32 ba_win_sz, u16 ssn,
9368c2ecf20Sopenharmony_ci			     enum hal_pn_type pn_type)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
9398c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
9408c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid;
9418c2ecf20Sopenharmony_ci	u32 hw_desc_sz;
9428c2ecf20Sopenharmony_ci	u32 *addr_aligned;
9438c2ecf20Sopenharmony_ci	void *vaddr;
9448c2ecf20Sopenharmony_ci	dma_addr_t paddr;
9458c2ecf20Sopenharmony_ci	int ret;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, vdev_id, peer_mac);
9508c2ecf20Sopenharmony_ci	if (!peer) {
9518c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to find the peer to set up rx tid\n");
9528c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
9538c2ecf20Sopenharmony_ci		return -ENOENT;
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	rx_tid = &peer->rx_tid[tid];
9578c2ecf20Sopenharmony_ci	/* Update the tid queue if it is already setup */
9588c2ecf20Sopenharmony_ci	if (rx_tid->active) {
9598c2ecf20Sopenharmony_ci		paddr = rx_tid->paddr;
9608c2ecf20Sopenharmony_ci		ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid,
9618c2ecf20Sopenharmony_ci						    ba_win_sz, ssn, true);
9628c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
9638c2ecf20Sopenharmony_ci		if (ret) {
9648c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to update reo for rx tid %d\n", tid);
9658c2ecf20Sopenharmony_ci			return ret;
9668c2ecf20Sopenharmony_ci		}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci		ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
9698c2ecf20Sopenharmony_ci							     peer_mac, paddr,
9708c2ecf20Sopenharmony_ci							     tid, 1, ba_win_sz);
9718c2ecf20Sopenharmony_ci		if (ret)
9728c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to send wmi command to update rx reorder queue, tid :%d (%d)\n",
9738c2ecf20Sopenharmony_ci				    tid, ret);
9748c2ecf20Sopenharmony_ci		return ret;
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	rx_tid->tid = tid;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	rx_tid->ba_win_sz = ba_win_sz;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	/* TODO: Optimize the memory allocation for qos tid based on the
9828c2ecf20Sopenharmony_ci	 * the actual BA window size in REO tid update path.
9838c2ecf20Sopenharmony_ci	 */
9848c2ecf20Sopenharmony_ci	if (tid == HAL_DESC_REO_NON_QOS_TID)
9858c2ecf20Sopenharmony_ci		hw_desc_sz = ath11k_hal_reo_qdesc_size(ba_win_sz, tid);
9868c2ecf20Sopenharmony_ci	else
9878c2ecf20Sopenharmony_ci		hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC);
9908c2ecf20Sopenharmony_ci	if (!vaddr) {
9918c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
9928c2ecf20Sopenharmony_ci		return -ENOMEM;
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz,
9988c2ecf20Sopenharmony_ci				   ssn, pn_type);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz,
10018c2ecf20Sopenharmony_ci			       DMA_BIDIRECTIONAL);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	ret = dma_mapping_error(ab->dev, paddr);
10048c2ecf20Sopenharmony_ci	if (ret) {
10058c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
10068c2ecf20Sopenharmony_ci		goto err_mem_free;
10078c2ecf20Sopenharmony_ci	}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	rx_tid->vaddr = vaddr;
10108c2ecf20Sopenharmony_ci	rx_tid->paddr = paddr;
10118c2ecf20Sopenharmony_ci	rx_tid->size = hw_desc_sz;
10128c2ecf20Sopenharmony_ci	rx_tid->active = true;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
10178c2ecf20Sopenharmony_ci						     paddr, tid, 1, ba_win_sz);
10188c2ecf20Sopenharmony_ci	if (ret) {
10198c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to setup rx reorder queue, tid :%d (%d)\n",
10208c2ecf20Sopenharmony_ci			    tid, ret);
10218c2ecf20Sopenharmony_ci		ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid);
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	return ret;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_cierr_mem_free:
10278c2ecf20Sopenharmony_ci	kfree(vaddr);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	return ret;
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ciint ath11k_dp_rx_ampdu_start(struct ath11k *ar,
10338c2ecf20Sopenharmony_ci			     struct ieee80211_ampdu_params *params)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
10368c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta = (void *)params->sta->drv_priv;
10378c2ecf20Sopenharmony_ci	int vdev_id = arsta->arvif->vdev_id;
10388c2ecf20Sopenharmony_ci	int ret;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	ret = ath11k_peer_rx_tid_setup(ar, params->sta->addr, vdev_id,
10418c2ecf20Sopenharmony_ci				       params->tid, params->buf_size,
10428c2ecf20Sopenharmony_ci				       params->ssn, arsta->pn_type);
10438c2ecf20Sopenharmony_ci	if (ret)
10448c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to setup rx tid %d\n", ret);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	return ret;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ciint ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
10508c2ecf20Sopenharmony_ci			    struct ieee80211_ampdu_params *params)
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
10538c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
10548c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta = (void *)params->sta->drv_priv;
10558c2ecf20Sopenharmony_ci	int vdev_id = arsta->arvif->vdev_id;
10568c2ecf20Sopenharmony_ci	dma_addr_t paddr;
10578c2ecf20Sopenharmony_ci	bool active;
10588c2ecf20Sopenharmony_ci	int ret;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, vdev_id, params->sta->addr);
10638c2ecf20Sopenharmony_ci	if (!peer) {
10648c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to find the peer to stop rx aggregation\n");
10658c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
10668c2ecf20Sopenharmony_ci		return -ENOENT;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	paddr = peer->rx_tid[params->tid].paddr;
10708c2ecf20Sopenharmony_ci	active = peer->rx_tid[params->tid].active;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	if (!active) {
10738c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
10748c2ecf20Sopenharmony_ci		return 0;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
10788c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
10798c2ecf20Sopenharmony_ci	if (ret) {
10808c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
10818c2ecf20Sopenharmony_ci			    params->tid, ret);
10828c2ecf20Sopenharmony_ci		return ret;
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
10868c2ecf20Sopenharmony_ci						     params->sta->addr, paddr,
10878c2ecf20Sopenharmony_ci						     params->tid, 1, 1);
10888c2ecf20Sopenharmony_ci	if (ret)
10898c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
10908c2ecf20Sopenharmony_ci			    ret);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	return ret;
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ciint ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif,
10968c2ecf20Sopenharmony_ci				       const u8 *peer_addr,
10978c2ecf20Sopenharmony_ci				       enum set_key_cmd key_cmd,
10988c2ecf20Sopenharmony_ci				       struct ieee80211_key_conf *key)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
11018c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
11028c2ecf20Sopenharmony_ci	struct ath11k_hal_reo_cmd cmd = {0};
11038c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
11048c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid;
11058c2ecf20Sopenharmony_ci	u8 tid;
11068c2ecf20Sopenharmony_ci	int ret = 0;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	/* NOTE: Enable PN/TSC replay check offload only for unicast frames.
11098c2ecf20Sopenharmony_ci	 * We use mac80211 PN/TSC replay check functionality for bcast/mcast
11108c2ecf20Sopenharmony_ci	 * for now.
11118c2ecf20Sopenharmony_ci	 */
11128c2ecf20Sopenharmony_ci	if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
11138c2ecf20Sopenharmony_ci		return 0;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS;
11168c2ecf20Sopenharmony_ci	cmd.upd0 |= HAL_REO_CMD_UPD0_PN |
11178c2ecf20Sopenharmony_ci		    HAL_REO_CMD_UPD0_PN_SIZE |
11188c2ecf20Sopenharmony_ci		    HAL_REO_CMD_UPD0_PN_VALID |
11198c2ecf20Sopenharmony_ci		    HAL_REO_CMD_UPD0_PN_CHECK |
11208c2ecf20Sopenharmony_ci		    HAL_REO_CMD_UPD0_SVLD;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	switch (key->cipher) {
11238c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
11248c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
11258c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
11268c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
11278c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
11288c2ecf20Sopenharmony_ci		if (key_cmd == SET_KEY) {
11298c2ecf20Sopenharmony_ci			cmd.upd1 |= HAL_REO_CMD_UPD1_PN_CHECK;
11308c2ecf20Sopenharmony_ci			cmd.pn_size = 48;
11318c2ecf20Sopenharmony_ci		}
11328c2ecf20Sopenharmony_ci		break;
11338c2ecf20Sopenharmony_ci	default:
11348c2ecf20Sopenharmony_ci		break;
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr);
11408c2ecf20Sopenharmony_ci	if (!peer) {
11418c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to find the peer to configure pn replay detection\n");
11428c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
11438c2ecf20Sopenharmony_ci		return -ENOENT;
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) {
11478c2ecf20Sopenharmony_ci		rx_tid = &peer->rx_tid[tid];
11488c2ecf20Sopenharmony_ci		if (!rx_tid->active)
11498c2ecf20Sopenharmony_ci			continue;
11508c2ecf20Sopenharmony_ci		cmd.addr_lo = lower_32_bits(rx_tid->paddr);
11518c2ecf20Sopenharmony_ci		cmd.addr_hi = upper_32_bits(rx_tid->paddr);
11528c2ecf20Sopenharmony_ci		ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid,
11538c2ecf20Sopenharmony_ci						HAL_REO_CMD_UPDATE_RX_QUEUE,
11548c2ecf20Sopenharmony_ci						&cmd, NULL);
11558c2ecf20Sopenharmony_ci		if (ret) {
11568c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to configure rx tid %d queue for pn replay detection %d\n",
11578c2ecf20Sopenharmony_ci				    tid, ret);
11588c2ecf20Sopenharmony_ci			break;
11598c2ecf20Sopenharmony_ci		}
11608c2ecf20Sopenharmony_ci	}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->ab->base_lock);
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	return ret;
11658c2ecf20Sopenharmony_ci}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_cistatic inline int ath11k_get_ppdu_user_index(struct htt_ppdu_stats *ppdu_stats,
11688c2ecf20Sopenharmony_ci					     u16 peer_id)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	int i;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	for (i = 0; i < HTT_PPDU_STATS_MAX_USERS - 1; i++) {
11738c2ecf20Sopenharmony_ci		if (ppdu_stats->user_stats[i].is_valid_peer_id) {
11748c2ecf20Sopenharmony_ci			if (peer_id == ppdu_stats->user_stats[i].peer_id)
11758c2ecf20Sopenharmony_ci				return i;
11768c2ecf20Sopenharmony_ci		} else {
11778c2ecf20Sopenharmony_ci			return i;
11788c2ecf20Sopenharmony_ci		}
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	return -EINVAL;
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic int ath11k_htt_tlv_ppdu_stats_parse(struct ath11k_base *ab,
11858c2ecf20Sopenharmony_ci					   u16 tag, u16 len, const void *ptr,
11868c2ecf20Sopenharmony_ci					   void *data)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	struct htt_ppdu_stats_info *ppdu_info;
11898c2ecf20Sopenharmony_ci	struct htt_ppdu_user_stats *user_stats;
11908c2ecf20Sopenharmony_ci	int cur_user;
11918c2ecf20Sopenharmony_ci	u16 peer_id;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	ppdu_info = (struct htt_ppdu_stats_info *)data;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	switch (tag) {
11968c2ecf20Sopenharmony_ci	case HTT_PPDU_STATS_TAG_COMMON:
11978c2ecf20Sopenharmony_ci		if (len < sizeof(struct htt_ppdu_stats_common)) {
11988c2ecf20Sopenharmony_ci			ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
11998c2ecf20Sopenharmony_ci				    len, tag);
12008c2ecf20Sopenharmony_ci			return -EINVAL;
12018c2ecf20Sopenharmony_ci		}
12028c2ecf20Sopenharmony_ci		memcpy((void *)&ppdu_info->ppdu_stats.common, ptr,
12038c2ecf20Sopenharmony_ci		       sizeof(struct htt_ppdu_stats_common));
12048c2ecf20Sopenharmony_ci		break;
12058c2ecf20Sopenharmony_ci	case HTT_PPDU_STATS_TAG_USR_RATE:
12068c2ecf20Sopenharmony_ci		if (len < sizeof(struct htt_ppdu_stats_user_rate)) {
12078c2ecf20Sopenharmony_ci			ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
12088c2ecf20Sopenharmony_ci				    len, tag);
12098c2ecf20Sopenharmony_ci			return -EINVAL;
12108c2ecf20Sopenharmony_ci		}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci		peer_id = ((struct htt_ppdu_stats_user_rate *)ptr)->sw_peer_id;
12138c2ecf20Sopenharmony_ci		cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats,
12148c2ecf20Sopenharmony_ci						      peer_id);
12158c2ecf20Sopenharmony_ci		if (cur_user < 0)
12168c2ecf20Sopenharmony_ci			return -EINVAL;
12178c2ecf20Sopenharmony_ci		user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user];
12188c2ecf20Sopenharmony_ci		user_stats->peer_id = peer_id;
12198c2ecf20Sopenharmony_ci		user_stats->is_valid_peer_id = true;
12208c2ecf20Sopenharmony_ci		memcpy((void *)&user_stats->rate, ptr,
12218c2ecf20Sopenharmony_ci		       sizeof(struct htt_ppdu_stats_user_rate));
12228c2ecf20Sopenharmony_ci		user_stats->tlv_flags |= BIT(tag);
12238c2ecf20Sopenharmony_ci		break;
12248c2ecf20Sopenharmony_ci	case HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON:
12258c2ecf20Sopenharmony_ci		if (len < sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)) {
12268c2ecf20Sopenharmony_ci			ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
12278c2ecf20Sopenharmony_ci				    len, tag);
12288c2ecf20Sopenharmony_ci			return -EINVAL;
12298c2ecf20Sopenharmony_ci		}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci		peer_id = ((struct htt_ppdu_stats_usr_cmpltn_cmn *)ptr)->sw_peer_id;
12328c2ecf20Sopenharmony_ci		cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats,
12338c2ecf20Sopenharmony_ci						      peer_id);
12348c2ecf20Sopenharmony_ci		if (cur_user < 0)
12358c2ecf20Sopenharmony_ci			return -EINVAL;
12368c2ecf20Sopenharmony_ci		user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user];
12378c2ecf20Sopenharmony_ci		user_stats->peer_id = peer_id;
12388c2ecf20Sopenharmony_ci		user_stats->is_valid_peer_id = true;
12398c2ecf20Sopenharmony_ci		memcpy((void *)&user_stats->cmpltn_cmn, ptr,
12408c2ecf20Sopenharmony_ci		       sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn));
12418c2ecf20Sopenharmony_ci		user_stats->tlv_flags |= BIT(tag);
12428c2ecf20Sopenharmony_ci		break;
12438c2ecf20Sopenharmony_ci	case HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS:
12448c2ecf20Sopenharmony_ci		if (len <
12458c2ecf20Sopenharmony_ci		    sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)) {
12468c2ecf20Sopenharmony_ci			ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
12478c2ecf20Sopenharmony_ci				    len, tag);
12488c2ecf20Sopenharmony_ci			return -EINVAL;
12498c2ecf20Sopenharmony_ci		}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci		peer_id =
12528c2ecf20Sopenharmony_ci		((struct htt_ppdu_stats_usr_cmpltn_ack_ba_status *)ptr)->sw_peer_id;
12538c2ecf20Sopenharmony_ci		cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats,
12548c2ecf20Sopenharmony_ci						      peer_id);
12558c2ecf20Sopenharmony_ci		if (cur_user < 0)
12568c2ecf20Sopenharmony_ci			return -EINVAL;
12578c2ecf20Sopenharmony_ci		user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user];
12588c2ecf20Sopenharmony_ci		user_stats->peer_id = peer_id;
12598c2ecf20Sopenharmony_ci		user_stats->is_valid_peer_id = true;
12608c2ecf20Sopenharmony_ci		memcpy((void *)&user_stats->ack_ba, ptr,
12618c2ecf20Sopenharmony_ci		       sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status));
12628c2ecf20Sopenharmony_ci		user_stats->tlv_flags |= BIT(tag);
12638c2ecf20Sopenharmony_ci		break;
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci	return 0;
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ciint ath11k_dp_htt_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len,
12698c2ecf20Sopenharmony_ci			   int (*iter)(struct ath11k_base *ar, u16 tag, u16 len,
12708c2ecf20Sopenharmony_ci				       const void *ptr, void *data),
12718c2ecf20Sopenharmony_ci			   void *data)
12728c2ecf20Sopenharmony_ci{
12738c2ecf20Sopenharmony_ci	const struct htt_tlv *tlv;
12748c2ecf20Sopenharmony_ci	const void *begin = ptr;
12758c2ecf20Sopenharmony_ci	u16 tlv_tag, tlv_len;
12768c2ecf20Sopenharmony_ci	int ret = -EINVAL;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	while (len > 0) {
12798c2ecf20Sopenharmony_ci		if (len < sizeof(*tlv)) {
12808c2ecf20Sopenharmony_ci			ath11k_err(ab, "htt tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",
12818c2ecf20Sopenharmony_ci				   ptr - begin, len, sizeof(*tlv));
12828c2ecf20Sopenharmony_ci			return -EINVAL;
12838c2ecf20Sopenharmony_ci		}
12848c2ecf20Sopenharmony_ci		tlv = (struct htt_tlv *)ptr;
12858c2ecf20Sopenharmony_ci		tlv_tag = FIELD_GET(HTT_TLV_TAG, tlv->header);
12868c2ecf20Sopenharmony_ci		tlv_len = FIELD_GET(HTT_TLV_LEN, tlv->header);
12878c2ecf20Sopenharmony_ci		ptr += sizeof(*tlv);
12888c2ecf20Sopenharmony_ci		len -= sizeof(*tlv);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		if (tlv_len > len) {
12918c2ecf20Sopenharmony_ci			ath11k_err(ab, "htt tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n",
12928c2ecf20Sopenharmony_ci				   tlv_tag, ptr - begin, len, tlv_len);
12938c2ecf20Sopenharmony_ci			return -EINVAL;
12948c2ecf20Sopenharmony_ci		}
12958c2ecf20Sopenharmony_ci		ret = iter(ab, tlv_tag, tlv_len, ptr, data);
12968c2ecf20Sopenharmony_ci		if (ret == -ENOMEM)
12978c2ecf20Sopenharmony_ci			return ret;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci		ptr += tlv_len;
13008c2ecf20Sopenharmony_ci		len -= tlv_len;
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci	return 0;
13038c2ecf20Sopenharmony_ci}
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_cistatic inline u32 ath11k_he_gi_to_nl80211_he_gi(u8 sgi)
13068c2ecf20Sopenharmony_ci{
13078c2ecf20Sopenharmony_ci	u32 ret = 0;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	switch (sgi) {
13108c2ecf20Sopenharmony_ci	case RX_MSDU_START_SGI_0_8_US:
13118c2ecf20Sopenharmony_ci		ret = NL80211_RATE_INFO_HE_GI_0_8;
13128c2ecf20Sopenharmony_ci		break;
13138c2ecf20Sopenharmony_ci	case RX_MSDU_START_SGI_1_6_US:
13148c2ecf20Sopenharmony_ci		ret = NL80211_RATE_INFO_HE_GI_1_6;
13158c2ecf20Sopenharmony_ci		break;
13168c2ecf20Sopenharmony_ci	case RX_MSDU_START_SGI_3_2_US:
13178c2ecf20Sopenharmony_ci		ret = NL80211_RATE_INFO_HE_GI_3_2;
13188c2ecf20Sopenharmony_ci		break;
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	return ret;
13228c2ecf20Sopenharmony_ci}
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_cistatic void
13258c2ecf20Sopenharmony_ciath11k_update_per_peer_tx_stats(struct ath11k *ar,
13268c2ecf20Sopenharmony_ci				struct htt_ppdu_stats *ppdu_stats, u8 user)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
13298c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
13308c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
13318c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta;
13328c2ecf20Sopenharmony_ci	struct htt_ppdu_stats_user_rate *user_rate;
13338c2ecf20Sopenharmony_ci	struct ath11k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats;
13348c2ecf20Sopenharmony_ci	struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user];
13358c2ecf20Sopenharmony_ci	struct htt_ppdu_stats_common *common = &ppdu_stats->common;
13368c2ecf20Sopenharmony_ci	int ret;
13378c2ecf20Sopenharmony_ci	u8 flags, mcs, nss, bw, sgi, dcm, rate_idx = 0;
13388c2ecf20Sopenharmony_ci	u32 succ_bytes = 0;
13398c2ecf20Sopenharmony_ci	u16 rate = 0, succ_pkts = 0;
13408c2ecf20Sopenharmony_ci	u32 tx_duration = 0;
13418c2ecf20Sopenharmony_ci	u8 tid = HTT_PPDU_STATS_NON_QOS_TID;
13428c2ecf20Sopenharmony_ci	bool is_ampdu = false;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	if (!usr_stats)
13458c2ecf20Sopenharmony_ci		return;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE)))
13488c2ecf20Sopenharmony_ci		return;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON))
13518c2ecf20Sopenharmony_ci		is_ampdu =
13528c2ecf20Sopenharmony_ci			HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	if (usr_stats->tlv_flags &
13558c2ecf20Sopenharmony_ci	    BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) {
13568c2ecf20Sopenharmony_ci		succ_bytes = usr_stats->ack_ba.success_bytes;
13578c2ecf20Sopenharmony_ci		succ_pkts = FIELD_GET(HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M,
13588c2ecf20Sopenharmony_ci				      usr_stats->ack_ba.info);
13598c2ecf20Sopenharmony_ci		tid = FIELD_GET(HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM,
13608c2ecf20Sopenharmony_ci				usr_stats->ack_ba.info);
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	if (common->fes_duration_us)
13648c2ecf20Sopenharmony_ci		tx_duration = common->fes_duration_us;
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	user_rate = &usr_stats->rate;
13678c2ecf20Sopenharmony_ci	flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags);
13688c2ecf20Sopenharmony_ci	bw = HTT_USR_RATE_BW(user_rate->rate_flags) - 2;
13698c2ecf20Sopenharmony_ci	nss = HTT_USR_RATE_NSS(user_rate->rate_flags) + 1;
13708c2ecf20Sopenharmony_ci	mcs = HTT_USR_RATE_MCS(user_rate->rate_flags);
13718c2ecf20Sopenharmony_ci	sgi = HTT_USR_RATE_GI(user_rate->rate_flags);
13728c2ecf20Sopenharmony_ci	dcm = HTT_USR_RATE_DCM(user_rate->rate_flags);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	/* Note: If host configured fixed rates and in some other special
13758c2ecf20Sopenharmony_ci	 * cases, the broadcast/management frames are sent in different rates.
13768c2ecf20Sopenharmony_ci	 * Firmware rate's control to be skipped for this?
13778c2ecf20Sopenharmony_ci	 */
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) {
13808c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Invalid HE mcs %hhd peer stats",  mcs);
13818c2ecf20Sopenharmony_ci		return;
13828c2ecf20Sopenharmony_ci	}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) {
13858c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Invalid HE mcs %hhd peer stats",  mcs);
13868c2ecf20Sopenharmony_ci		return;
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH11K_VHT_MCS_MAX) {
13908c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Invalid VHT mcs %hhd peer stats",  mcs);
13918c2ecf20Sopenharmony_ci		return;
13928c2ecf20Sopenharmony_ci	}
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH11K_HT_MCS_MAX || nss < 1)) {
13958c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Invalid HT mcs %hhd nss %hhd peer stats",
13968c2ecf20Sopenharmony_ci			    mcs, nss);
13978c2ecf20Sopenharmony_ci		return;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) {
14018c2ecf20Sopenharmony_ci		ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
14028c2ecf20Sopenharmony_ci							    flags,
14038c2ecf20Sopenharmony_ci							    &rate_idx,
14048c2ecf20Sopenharmony_ci							    &rate);
14058c2ecf20Sopenharmony_ci		if (ret < 0)
14068c2ecf20Sopenharmony_ci			return;
14078c2ecf20Sopenharmony_ci	}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	rcu_read_lock();
14108c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
14118c2ecf20Sopenharmony_ci	peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	if (!peer || !peer->sta) {
14148c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
14158c2ecf20Sopenharmony_ci		rcu_read_unlock();
14168c2ecf20Sopenharmony_ci		return;
14178c2ecf20Sopenharmony_ci	}
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	sta = peer->sta;
14208c2ecf20Sopenharmony_ci	arsta = (struct ath11k_sta *)sta->drv_priv;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	memset(&arsta->txrate, 0, sizeof(arsta->txrate));
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	switch (flags) {
14258c2ecf20Sopenharmony_ci	case WMI_RATE_PREAMBLE_OFDM:
14268c2ecf20Sopenharmony_ci		arsta->txrate.legacy = rate;
14278c2ecf20Sopenharmony_ci		break;
14288c2ecf20Sopenharmony_ci	case WMI_RATE_PREAMBLE_CCK:
14298c2ecf20Sopenharmony_ci		arsta->txrate.legacy = rate;
14308c2ecf20Sopenharmony_ci		break;
14318c2ecf20Sopenharmony_ci	case WMI_RATE_PREAMBLE_HT:
14328c2ecf20Sopenharmony_ci		arsta->txrate.mcs = mcs + 8 * (nss - 1);
14338c2ecf20Sopenharmony_ci		arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
14348c2ecf20Sopenharmony_ci		if (sgi)
14358c2ecf20Sopenharmony_ci			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
14368c2ecf20Sopenharmony_ci		break;
14378c2ecf20Sopenharmony_ci	case WMI_RATE_PREAMBLE_VHT:
14388c2ecf20Sopenharmony_ci		arsta->txrate.mcs = mcs;
14398c2ecf20Sopenharmony_ci		arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
14408c2ecf20Sopenharmony_ci		if (sgi)
14418c2ecf20Sopenharmony_ci			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
14428c2ecf20Sopenharmony_ci		break;
14438c2ecf20Sopenharmony_ci	case WMI_RATE_PREAMBLE_HE:
14448c2ecf20Sopenharmony_ci		arsta->txrate.mcs = mcs;
14458c2ecf20Sopenharmony_ci		arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS;
14468c2ecf20Sopenharmony_ci		arsta->txrate.he_dcm = dcm;
14478c2ecf20Sopenharmony_ci		arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi);
14488c2ecf20Sopenharmony_ci		arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc(
14498c2ecf20Sopenharmony_ci						(user_rate->ru_end -
14508c2ecf20Sopenharmony_ci						 user_rate->ru_start) + 1);
14518c2ecf20Sopenharmony_ci		break;
14528c2ecf20Sopenharmony_ci	}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	arsta->txrate.nss = nss;
14558c2ecf20Sopenharmony_ci	arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
14568c2ecf20Sopenharmony_ci	arsta->tx_duration += tx_duration;
14578c2ecf20Sopenharmony_ci	memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info));
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	/* PPDU stats reported for mgmt packet doesn't have valid tx bytes.
14608c2ecf20Sopenharmony_ci	 * So skip peer stats update for mgmt packets.
14618c2ecf20Sopenharmony_ci	 */
14628c2ecf20Sopenharmony_ci	if (tid < HTT_PPDU_STATS_NON_QOS_TID) {
14638c2ecf20Sopenharmony_ci		memset(peer_stats, 0, sizeof(*peer_stats));
14648c2ecf20Sopenharmony_ci		peer_stats->succ_pkts = succ_pkts;
14658c2ecf20Sopenharmony_ci		peer_stats->succ_bytes = succ_bytes;
14668c2ecf20Sopenharmony_ci		peer_stats->is_ampdu = is_ampdu;
14678c2ecf20Sopenharmony_ci		peer_stats->duration = tx_duration;
14688c2ecf20Sopenharmony_ci		peer_stats->ba_fails =
14698c2ecf20Sopenharmony_ci			HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) +
14708c2ecf20Sopenharmony_ci			HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci		if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
14738c2ecf20Sopenharmony_ci			ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
14748c2ecf20Sopenharmony_ci	}
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
14778c2ecf20Sopenharmony_ci	rcu_read_unlock();
14788c2ecf20Sopenharmony_ci}
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_cistatic void ath11k_htt_update_ppdu_stats(struct ath11k *ar,
14818c2ecf20Sopenharmony_ci					 struct htt_ppdu_stats *ppdu_stats)
14828c2ecf20Sopenharmony_ci{
14838c2ecf20Sopenharmony_ci	u8 user;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	for (user = 0; user < HTT_PPDU_STATS_MAX_USERS - 1; user++)
14868c2ecf20Sopenharmony_ci		ath11k_update_per_peer_tx_stats(ar, ppdu_stats, user);
14878c2ecf20Sopenharmony_ci}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_cistatic
14908c2ecf20Sopenharmony_cistruct htt_ppdu_stats_info *ath11k_dp_htt_get_ppdu_desc(struct ath11k *ar,
14918c2ecf20Sopenharmony_ci							u32 ppdu_id)
14928c2ecf20Sopenharmony_ci{
14938c2ecf20Sopenharmony_ci	struct htt_ppdu_stats_info *ppdu_info;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
14968c2ecf20Sopenharmony_ci	if (!list_empty(&ar->ppdu_stats_info)) {
14978c2ecf20Sopenharmony_ci		list_for_each_entry(ppdu_info, &ar->ppdu_stats_info, list) {
14988c2ecf20Sopenharmony_ci			if (ppdu_info->ppdu_id == ppdu_id) {
14998c2ecf20Sopenharmony_ci				spin_unlock_bh(&ar->data_lock);
15008c2ecf20Sopenharmony_ci				return ppdu_info;
15018c2ecf20Sopenharmony_ci			}
15028c2ecf20Sopenharmony_ci		}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci		if (ar->ppdu_stat_list_depth > HTT_PPDU_DESC_MAX_DEPTH) {
15058c2ecf20Sopenharmony_ci			ppdu_info = list_first_entry(&ar->ppdu_stats_info,
15068c2ecf20Sopenharmony_ci						     typeof(*ppdu_info), list);
15078c2ecf20Sopenharmony_ci			list_del(&ppdu_info->list);
15088c2ecf20Sopenharmony_ci			ar->ppdu_stat_list_depth--;
15098c2ecf20Sopenharmony_ci			ath11k_htt_update_ppdu_stats(ar, &ppdu_info->ppdu_stats);
15108c2ecf20Sopenharmony_ci			kfree(ppdu_info);
15118c2ecf20Sopenharmony_ci		}
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	ppdu_info = kzalloc(sizeof(*ppdu_info), GFP_ATOMIC);
15168c2ecf20Sopenharmony_ci	if (!ppdu_info)
15178c2ecf20Sopenharmony_ci		return NULL;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
15208c2ecf20Sopenharmony_ci	list_add_tail(&ppdu_info->list, &ar->ppdu_stats_info);
15218c2ecf20Sopenharmony_ci	ar->ppdu_stat_list_depth++;
15228c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	return ppdu_info;
15258c2ecf20Sopenharmony_ci}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_cistatic int ath11k_htt_pull_ppdu_stats(struct ath11k_base *ab,
15288c2ecf20Sopenharmony_ci				      struct sk_buff *skb)
15298c2ecf20Sopenharmony_ci{
15308c2ecf20Sopenharmony_ci	struct ath11k_htt_ppdu_stats_msg *msg;
15318c2ecf20Sopenharmony_ci	struct htt_ppdu_stats_info *ppdu_info;
15328c2ecf20Sopenharmony_ci	struct ath11k *ar;
15338c2ecf20Sopenharmony_ci	int ret;
15348c2ecf20Sopenharmony_ci	u8 pdev_id;
15358c2ecf20Sopenharmony_ci	u32 ppdu_id, len;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	msg = (struct ath11k_htt_ppdu_stats_msg *)skb->data;
15388c2ecf20Sopenharmony_ci	len = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PAYLOAD_SIZE, msg->info);
15398c2ecf20Sopenharmony_ci	pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, msg->info);
15408c2ecf20Sopenharmony_ci	ppdu_id = msg->ppdu_id;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	rcu_read_lock();
15438c2ecf20Sopenharmony_ci	ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id);
15448c2ecf20Sopenharmony_ci	if (!ar) {
15458c2ecf20Sopenharmony_ci		ret = -EINVAL;
15468c2ecf20Sopenharmony_ci		goto exit;
15478c2ecf20Sopenharmony_ci	}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar))
15508c2ecf20Sopenharmony_ci		trace_ath11k_htt_ppdu_stats(ar, skb->data, len);
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	ppdu_info = ath11k_dp_htt_get_ppdu_desc(ar, ppdu_id);
15538c2ecf20Sopenharmony_ci	if (!ppdu_info) {
15548c2ecf20Sopenharmony_ci		ret = -EINVAL;
15558c2ecf20Sopenharmony_ci		goto exit;
15568c2ecf20Sopenharmony_ci	}
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	ppdu_info->ppdu_id = ppdu_id;
15598c2ecf20Sopenharmony_ci	ret = ath11k_dp_htt_tlv_iter(ab, msg->data, len,
15608c2ecf20Sopenharmony_ci				     ath11k_htt_tlv_ppdu_stats_parse,
15618c2ecf20Sopenharmony_ci				     (void *)ppdu_info);
15628c2ecf20Sopenharmony_ci	if (ret) {
15638c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Failed to parse tlv %d\n", ret);
15648c2ecf20Sopenharmony_ci		goto exit;
15658c2ecf20Sopenharmony_ci	}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ciexit:
15688c2ecf20Sopenharmony_ci	rcu_read_unlock();
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	return ret;
15718c2ecf20Sopenharmony_ci}
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_cistatic void ath11k_htt_pktlog(struct ath11k_base *ab, struct sk_buff *skb)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	struct htt_pktlog_msg *data = (struct htt_pktlog_msg *)skb->data;
15768c2ecf20Sopenharmony_ci	struct ath_pktlog_hdr *hdr = (struct ath_pktlog_hdr *)data;
15778c2ecf20Sopenharmony_ci	struct ath11k *ar;
15788c2ecf20Sopenharmony_ci	u8 pdev_id;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, data->hdr);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	rcu_read_lock();
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id);
15858c2ecf20Sopenharmony_ci	if (!ar) {
15868c2ecf20Sopenharmony_ci		ath11k_warn(ab, "invalid pdev id %d on htt pktlog\n", pdev_id);
15878c2ecf20Sopenharmony_ci		goto out;
15888c2ecf20Sopenharmony_ci	}
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	trace_ath11k_htt_pktlog(ar, data->payload, hdr->size,
15918c2ecf20Sopenharmony_ci				ar->ab->pktlog_defs_checksum);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ciout:
15948c2ecf20Sopenharmony_ci	rcu_read_unlock();
15958c2ecf20Sopenharmony_ci}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_cistatic void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab,
15988c2ecf20Sopenharmony_ci						  struct sk_buff *skb)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	u32 *data = (u32 *)skb->data;
16018c2ecf20Sopenharmony_ci	u8 pdev_id, ring_type, ring_id, pdev_idx;
16028c2ecf20Sopenharmony_ci	u16 hp, tp;
16038c2ecf20Sopenharmony_ci	u32 backpressure_time;
16048c2ecf20Sopenharmony_ci	struct ath11k_bp_stats *bp_stats;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	pdev_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_PDEV_ID_M, *data);
16078c2ecf20Sopenharmony_ci	ring_type = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_TYPE_M, *data);
16088c2ecf20Sopenharmony_ci	ring_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_ID_M, *data);
16098c2ecf20Sopenharmony_ci	++data;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	hp = FIELD_GET(HTT_BACKPRESSURE_EVENT_HP_M, *data);
16128c2ecf20Sopenharmony_ci	tp = FIELD_GET(HTT_BACKPRESSURE_EVENT_TP_M, *data);
16138c2ecf20Sopenharmony_ci	++data;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	backpressure_time = *data;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n",
16188c2ecf20Sopenharmony_ci		   pdev_id, ring_type, ring_id, hp, tp, backpressure_time);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	if (ring_type == HTT_BACKPRESSURE_UMAC_RING_TYPE) {
16218c2ecf20Sopenharmony_ci		if (ring_id >= HTT_SW_UMAC_RING_IDX_MAX)
16228c2ecf20Sopenharmony_ci			return;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci		bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[ring_id];
16258c2ecf20Sopenharmony_ci	} else if (ring_type == HTT_BACKPRESSURE_LMAC_RING_TYPE) {
16268c2ecf20Sopenharmony_ci		pdev_idx = DP_HW2SW_MACID(pdev_id);
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci		if (ring_id >= HTT_SW_LMAC_RING_IDX_MAX || pdev_idx >= MAX_RADIOS)
16298c2ecf20Sopenharmony_ci			return;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci		bp_stats = &ab->soc_stats.bp_stats.lmac_ring_bp_stats[ring_id][pdev_idx];
16328c2ecf20Sopenharmony_ci	} else {
16338c2ecf20Sopenharmony_ci		ath11k_warn(ab, "unknown ring type received in htt bp event %d\n",
16348c2ecf20Sopenharmony_ci			    ring_type);
16358c2ecf20Sopenharmony_ci		return;
16368c2ecf20Sopenharmony_ci	}
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
16398c2ecf20Sopenharmony_ci	bp_stats->hp = hp;
16408c2ecf20Sopenharmony_ci	bp_stats->tp = tp;
16418c2ecf20Sopenharmony_ci	bp_stats->count++;
16428c2ecf20Sopenharmony_ci	bp_stats->jiffies = jiffies;
16438c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
16448c2ecf20Sopenharmony_ci}
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_civoid ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab,
16478c2ecf20Sopenharmony_ci				       struct sk_buff *skb)
16488c2ecf20Sopenharmony_ci{
16498c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
16508c2ecf20Sopenharmony_ci	struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data;
16518c2ecf20Sopenharmony_ci	enum htt_t2h_msg_type type = FIELD_GET(HTT_T2H_MSG_TYPE, *(u32 *)resp);
16528c2ecf20Sopenharmony_ci	u16 peer_id;
16538c2ecf20Sopenharmony_ci	u8 vdev_id;
16548c2ecf20Sopenharmony_ci	u8 mac_addr[ETH_ALEN];
16558c2ecf20Sopenharmony_ci	u16 peer_mac_h16;
16568c2ecf20Sopenharmony_ci	u16 ast_hash;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "dp_htt rx msg type :0x%0x\n", type);
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	switch (type) {
16618c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_VERSION_CONF:
16628c2ecf20Sopenharmony_ci		dp->htt_tgt_ver_major = FIELD_GET(HTT_T2H_VERSION_CONF_MAJOR,
16638c2ecf20Sopenharmony_ci						  resp->version_msg.version);
16648c2ecf20Sopenharmony_ci		dp->htt_tgt_ver_minor = FIELD_GET(HTT_T2H_VERSION_CONF_MINOR,
16658c2ecf20Sopenharmony_ci						  resp->version_msg.version);
16668c2ecf20Sopenharmony_ci		complete(&dp->htt_tgt_version_received);
16678c2ecf20Sopenharmony_ci		break;
16688c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_PEER_MAP:
16698c2ecf20Sopenharmony_ci		vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID,
16708c2ecf20Sopenharmony_ci				    resp->peer_map_ev.info);
16718c2ecf20Sopenharmony_ci		peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID,
16728c2ecf20Sopenharmony_ci				    resp->peer_map_ev.info);
16738c2ecf20Sopenharmony_ci		peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16,
16748c2ecf20Sopenharmony_ci					 resp->peer_map_ev.info1);
16758c2ecf20Sopenharmony_ci		ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32,
16768c2ecf20Sopenharmony_ci				       peer_mac_h16, mac_addr);
16778c2ecf20Sopenharmony_ci		ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, 0);
16788c2ecf20Sopenharmony_ci		break;
16798c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_PEER_MAP2:
16808c2ecf20Sopenharmony_ci		vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID,
16818c2ecf20Sopenharmony_ci				    resp->peer_map_ev.info);
16828c2ecf20Sopenharmony_ci		peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID,
16838c2ecf20Sopenharmony_ci				    resp->peer_map_ev.info);
16848c2ecf20Sopenharmony_ci		peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16,
16858c2ecf20Sopenharmony_ci					 resp->peer_map_ev.info1);
16868c2ecf20Sopenharmony_ci		ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32,
16878c2ecf20Sopenharmony_ci				       peer_mac_h16, mac_addr);
16888c2ecf20Sopenharmony_ci		ast_hash = FIELD_GET(HTT_T2H_PEER_MAP_INFO2_AST_HASH_VAL,
16898c2ecf20Sopenharmony_ci				     resp->peer_map_ev.info2);
16908c2ecf20Sopenharmony_ci		ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash);
16918c2ecf20Sopenharmony_ci		break;
16928c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_PEER_UNMAP:
16938c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_PEER_UNMAP2:
16948c2ecf20Sopenharmony_ci		peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID,
16958c2ecf20Sopenharmony_ci				    resp->peer_unmap_ev.info);
16968c2ecf20Sopenharmony_ci		ath11k_peer_unmap_event(ab, peer_id);
16978c2ecf20Sopenharmony_ci		break;
16988c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_PPDU_STATS_IND:
16998c2ecf20Sopenharmony_ci		ath11k_htt_pull_ppdu_stats(ab, skb);
17008c2ecf20Sopenharmony_ci		break;
17018c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_EXT_STATS_CONF:
17028c2ecf20Sopenharmony_ci		ath11k_debugfs_htt_ext_stats_handler(ab, skb);
17038c2ecf20Sopenharmony_ci		break;
17048c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_PKTLOG:
17058c2ecf20Sopenharmony_ci		ath11k_htt_pktlog(ab, skb);
17068c2ecf20Sopenharmony_ci		break;
17078c2ecf20Sopenharmony_ci	case HTT_T2H_MSG_TYPE_BKPRESSURE_EVENT_IND:
17088c2ecf20Sopenharmony_ci		ath11k_htt_backpressure_event_handler(ab, skb);
17098c2ecf20Sopenharmony_ci		break;
17108c2ecf20Sopenharmony_ci	default:
17118c2ecf20Sopenharmony_ci		ath11k_warn(ab, "htt event %d not handled\n", type);
17128c2ecf20Sopenharmony_ci		break;
17138c2ecf20Sopenharmony_ci	}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
17168c2ecf20Sopenharmony_ci}
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
17198c2ecf20Sopenharmony_ci				      struct sk_buff_head *msdu_list,
17208c2ecf20Sopenharmony_ci				      struct sk_buff *first, struct sk_buff *last,
17218c2ecf20Sopenharmony_ci				      u8 l3pad_bytes, int msdu_len)
17228c2ecf20Sopenharmony_ci{
17238c2ecf20Sopenharmony_ci	struct sk_buff *skb;
17248c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first);
17258c2ecf20Sopenharmony_ci	int buf_first_hdr_len, buf_first_len;
17268c2ecf20Sopenharmony_ci	struct hal_rx_desc *ldesc;
17278c2ecf20Sopenharmony_ci	int space_extra;
17288c2ecf20Sopenharmony_ci	int rem_len;
17298c2ecf20Sopenharmony_ci	int buf_len;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	/* As the msdu is spread across multiple rx buffers,
17328c2ecf20Sopenharmony_ci	 * find the offset to the start of msdu for computing
17338c2ecf20Sopenharmony_ci	 * the length of the msdu in the first buffer.
17348c2ecf20Sopenharmony_ci	 */
17358c2ecf20Sopenharmony_ci	buf_first_hdr_len = HAL_RX_DESC_SIZE + l3pad_bytes;
17368c2ecf20Sopenharmony_ci	buf_first_len = DP_RX_BUFFER_SIZE - buf_first_hdr_len;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(msdu_len <= buf_first_len)) {
17398c2ecf20Sopenharmony_ci		skb_put(first, buf_first_hdr_len + msdu_len);
17408c2ecf20Sopenharmony_ci		skb_pull(first, buf_first_hdr_len);
17418c2ecf20Sopenharmony_ci		return 0;
17428c2ecf20Sopenharmony_ci	}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	ldesc = (struct hal_rx_desc *)last->data;
17458c2ecf20Sopenharmony_ci	rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ldesc);
17468c2ecf20Sopenharmony_ci	rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ldesc);
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	/* MSDU spans over multiple buffers because the length of the MSDU
17498c2ecf20Sopenharmony_ci	 * exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data
17508c2ecf20Sopenharmony_ci	 * in the first buf is of length DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE.
17518c2ecf20Sopenharmony_ci	 */
17528c2ecf20Sopenharmony_ci	skb_put(first, DP_RX_BUFFER_SIZE);
17538c2ecf20Sopenharmony_ci	skb_pull(first, buf_first_hdr_len);
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	/* When an MSDU spread over multiple buffers attention, MSDU_END and
17568c2ecf20Sopenharmony_ci	 * MPDU_END tlvs are valid only in the last buffer. Copy those tlvs.
17578c2ecf20Sopenharmony_ci	 */
17588c2ecf20Sopenharmony_ci	ath11k_dp_rx_desc_end_tlv_copy(rxcb->rx_desc, ldesc);
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	space_extra = msdu_len - (buf_first_len + skb_tailroom(first));
17618c2ecf20Sopenharmony_ci	if (space_extra > 0 &&
17628c2ecf20Sopenharmony_ci	    (pskb_expand_head(first, 0, space_extra, GFP_ATOMIC) < 0)) {
17638c2ecf20Sopenharmony_ci		/* Free up all buffers of the MSDU */
17648c2ecf20Sopenharmony_ci		while ((skb = __skb_dequeue(msdu_list)) != NULL) {
17658c2ecf20Sopenharmony_ci			rxcb = ATH11K_SKB_RXCB(skb);
17668c2ecf20Sopenharmony_ci			if (!rxcb->is_continuation) {
17678c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb);
17688c2ecf20Sopenharmony_ci				break;
17698c2ecf20Sopenharmony_ci			}
17708c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
17718c2ecf20Sopenharmony_ci		}
17728c2ecf20Sopenharmony_ci		return -ENOMEM;
17738c2ecf20Sopenharmony_ci	}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	rem_len = msdu_len - buf_first_len;
17768c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) {
17778c2ecf20Sopenharmony_ci		rxcb = ATH11K_SKB_RXCB(skb);
17788c2ecf20Sopenharmony_ci		if (rxcb->is_continuation)
17798c2ecf20Sopenharmony_ci			buf_len = DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE;
17808c2ecf20Sopenharmony_ci		else
17818c2ecf20Sopenharmony_ci			buf_len = rem_len;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci		if (buf_len > (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE)) {
17848c2ecf20Sopenharmony_ci			WARN_ON_ONCE(1);
17858c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
17868c2ecf20Sopenharmony_ci			return -EINVAL;
17878c2ecf20Sopenharmony_ci		}
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci		skb_put(skb, buf_len + HAL_RX_DESC_SIZE);
17908c2ecf20Sopenharmony_ci		skb_pull(skb, HAL_RX_DESC_SIZE);
17918c2ecf20Sopenharmony_ci		skb_copy_from_linear_data(skb, skb_put(first, buf_len),
17928c2ecf20Sopenharmony_ci					  buf_len);
17938c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci		rem_len -= buf_len;
17968c2ecf20Sopenharmony_ci		if (!rxcb->is_continuation)
17978c2ecf20Sopenharmony_ci			break;
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	return 0;
18018c2ecf20Sopenharmony_ci}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_cistatic struct sk_buff *ath11k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list,
18048c2ecf20Sopenharmony_ci						      struct sk_buff *first)
18058c2ecf20Sopenharmony_ci{
18068c2ecf20Sopenharmony_ci	struct sk_buff *skb;
18078c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first);
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	if (!rxcb->is_continuation)
18108c2ecf20Sopenharmony_ci		return first;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	skb_queue_walk(msdu_list, skb) {
18138c2ecf20Sopenharmony_ci		rxcb = ATH11K_SKB_RXCB(skb);
18148c2ecf20Sopenharmony_ci		if (!rxcb->is_continuation)
18158c2ecf20Sopenharmony_ci			return skb;
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	return NULL;
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_csum_offload(struct sk_buff *msdu)
18228c2ecf20Sopenharmony_ci{
18238c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
18248c2ecf20Sopenharmony_ci	bool ip_csum_fail, l4_csum_fail;
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	ip_csum_fail = ath11k_dp_rx_h_attn_ip_cksum_fail(rxcb->rx_desc);
18278c2ecf20Sopenharmony_ci	l4_csum_fail = ath11k_dp_rx_h_attn_l4_cksum_fail(rxcb->rx_desc);
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	msdu->ip_summed = (ip_csum_fail || l4_csum_fail) ?
18308c2ecf20Sopenharmony_ci			  CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
18318c2ecf20Sopenharmony_ci}
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar,
18348c2ecf20Sopenharmony_ci				       enum hal_encrypt_type enctype)
18358c2ecf20Sopenharmony_ci{
18368c2ecf20Sopenharmony_ci	switch (enctype) {
18378c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_OPEN:
18388c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
18398c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_TKIP_MIC:
18408c2ecf20Sopenharmony_ci		return 0;
18418c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_CCMP_128:
18428c2ecf20Sopenharmony_ci		return IEEE80211_CCMP_MIC_LEN;
18438c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_CCMP_256:
18448c2ecf20Sopenharmony_ci		return IEEE80211_CCMP_256_MIC_LEN;
18458c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_GCMP_128:
18468c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_AES_GCMP_256:
18478c2ecf20Sopenharmony_ci		return IEEE80211_GCMP_MIC_LEN;
18488c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_40:
18498c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_104:
18508c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_128:
18518c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4:
18528c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WAPI:
18538c2ecf20Sopenharmony_ci		break;
18548c2ecf20Sopenharmony_ci	}
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	ath11k_warn(ar->ab, "unsupported encryption type %d for mic len\n", enctype);
18578c2ecf20Sopenharmony_ci	return 0;
18588c2ecf20Sopenharmony_ci}
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_crypto_param_len(struct ath11k *ar,
18618c2ecf20Sopenharmony_ci					 enum hal_encrypt_type enctype)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	switch (enctype) {
18648c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_OPEN:
18658c2ecf20Sopenharmony_ci		return 0;
18668c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
18678c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_TKIP_MIC:
18688c2ecf20Sopenharmony_ci		return IEEE80211_TKIP_IV_LEN;
18698c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_CCMP_128:
18708c2ecf20Sopenharmony_ci		return IEEE80211_CCMP_HDR_LEN;
18718c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_CCMP_256:
18728c2ecf20Sopenharmony_ci		return IEEE80211_CCMP_256_HDR_LEN;
18738c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_GCMP_128:
18748c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_AES_GCMP_256:
18758c2ecf20Sopenharmony_ci		return IEEE80211_GCMP_HDR_LEN;
18768c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_40:
18778c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_104:
18788c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_128:
18798c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4:
18808c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WAPI:
18818c2ecf20Sopenharmony_ci		break;
18828c2ecf20Sopenharmony_ci	}
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype);
18858c2ecf20Sopenharmony_ci	return 0;
18868c2ecf20Sopenharmony_ci}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_crypto_icv_len(struct ath11k *ar,
18898c2ecf20Sopenharmony_ci				       enum hal_encrypt_type enctype)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	switch (enctype) {
18928c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_OPEN:
18938c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_CCMP_128:
18948c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_CCMP_256:
18958c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_GCMP_128:
18968c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_AES_GCMP_256:
18978c2ecf20Sopenharmony_ci		return 0;
18988c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
18998c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_TKIP_MIC:
19008c2ecf20Sopenharmony_ci		return IEEE80211_TKIP_ICV_LEN;
19018c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_40:
19028c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_104:
19038c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WEP_128:
19048c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4:
19058c2ecf20Sopenharmony_ci	case HAL_ENCRYPT_TYPE_WAPI:
19068c2ecf20Sopenharmony_ci		break;
19078c2ecf20Sopenharmony_ci	}
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype);
19108c2ecf20Sopenharmony_ci	return 0;
19118c2ecf20Sopenharmony_ci}
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar,
19148c2ecf20Sopenharmony_ci					 struct sk_buff *msdu,
19158c2ecf20Sopenharmony_ci					 u8 *first_hdr,
19168c2ecf20Sopenharmony_ci					 enum hal_encrypt_type enctype,
19178c2ecf20Sopenharmony_ci					 struct ieee80211_rx_status *status)
19188c2ecf20Sopenharmony_ci{
19198c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
19208c2ecf20Sopenharmony_ci	u8 decap_hdr[DP_MAX_NWIFI_HDR_LEN];
19218c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
19228c2ecf20Sopenharmony_ci	size_t hdr_len;
19238c2ecf20Sopenharmony_ci	u8 da[ETH_ALEN];
19248c2ecf20Sopenharmony_ci	u8 sa[ETH_ALEN];
19258c2ecf20Sopenharmony_ci	u16 qos_ctl = 0;
19268c2ecf20Sopenharmony_ci	u8 *qos;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	/* copy SA & DA and pull decapped header */
19298c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)msdu->data;
19308c2ecf20Sopenharmony_ci	hdr_len = ieee80211_hdrlen(hdr->frame_control);
19318c2ecf20Sopenharmony_ci	ether_addr_copy(da, ieee80211_get_DA(hdr));
19328c2ecf20Sopenharmony_ci	ether_addr_copy(sa, ieee80211_get_SA(hdr));
19338c2ecf20Sopenharmony_ci	skb_pull(msdu, ieee80211_hdrlen(hdr->frame_control));
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	if (rxcb->is_first_msdu) {
19368c2ecf20Sopenharmony_ci		/* original 802.11 header is valid for the first msdu
19378c2ecf20Sopenharmony_ci		 * hence we can reuse the same header
19388c2ecf20Sopenharmony_ci		 */
19398c2ecf20Sopenharmony_ci		hdr = (struct ieee80211_hdr *)first_hdr;
19408c2ecf20Sopenharmony_ci		hdr_len = ieee80211_hdrlen(hdr->frame_control);
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci		/* Each A-MSDU subframe will be reported as a separate MSDU,
19438c2ecf20Sopenharmony_ci		 * so strip the A-MSDU bit from QoS Ctl.
19448c2ecf20Sopenharmony_ci		 */
19458c2ecf20Sopenharmony_ci		if (ieee80211_is_data_qos(hdr->frame_control)) {
19468c2ecf20Sopenharmony_ci			qos = ieee80211_get_qos_ctl(hdr);
19478c2ecf20Sopenharmony_ci			qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
19488c2ecf20Sopenharmony_ci		}
19498c2ecf20Sopenharmony_ci	} else {
19508c2ecf20Sopenharmony_ci		/*  Rebuild qos header if this is a middle/last msdu */
19518c2ecf20Sopenharmony_ci		hdr->frame_control |= __cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci		/* Reset the order bit as the HT_Control header is stripped */
19548c2ecf20Sopenharmony_ci		hdr->frame_control &= ~(__cpu_to_le16(IEEE80211_FCTL_ORDER));
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci		qos_ctl = rxcb->tid;
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci		if (ath11k_dp_rx_h_msdu_start_mesh_ctl_present(rxcb->rx_desc))
19598c2ecf20Sopenharmony_ci			qos_ctl |= IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci		/* TODO Add other QoS ctl fields when required */
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci		/* copy decap header before overwriting for reuse below */
19648c2ecf20Sopenharmony_ci		memcpy(decap_hdr, (uint8_t *)hdr, hdr_len);
19658c2ecf20Sopenharmony_ci	}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
19688c2ecf20Sopenharmony_ci		memcpy(skb_push(msdu,
19698c2ecf20Sopenharmony_ci				ath11k_dp_rx_crypto_param_len(ar, enctype)),
19708c2ecf20Sopenharmony_ci		       (void *)hdr + hdr_len,
19718c2ecf20Sopenharmony_ci		       ath11k_dp_rx_crypto_param_len(ar, enctype));
19728c2ecf20Sopenharmony_ci	}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	if (!rxcb->is_first_msdu) {
19758c2ecf20Sopenharmony_ci		memcpy(skb_push(msdu,
19768c2ecf20Sopenharmony_ci				IEEE80211_QOS_CTL_LEN), &qos_ctl,
19778c2ecf20Sopenharmony_ci				IEEE80211_QOS_CTL_LEN);
19788c2ecf20Sopenharmony_ci		memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len);
19798c2ecf20Sopenharmony_ci		return;
19808c2ecf20Sopenharmony_ci	}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	/* original 802.11 header has a different DA and in
19858c2ecf20Sopenharmony_ci	 * case of 4addr it may also have different SA
19868c2ecf20Sopenharmony_ci	 */
19878c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)msdu->data;
19888c2ecf20Sopenharmony_ci	ether_addr_copy(ieee80211_get_DA(hdr), da);
19898c2ecf20Sopenharmony_ci	ether_addr_copy(ieee80211_get_SA(hdr), sa);
19908c2ecf20Sopenharmony_ci}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_raw(struct ath11k *ar, struct sk_buff *msdu,
19938c2ecf20Sopenharmony_ci				       enum hal_encrypt_type enctype,
19948c2ecf20Sopenharmony_ci				       struct ieee80211_rx_status *status,
19958c2ecf20Sopenharmony_ci				       bool decrypted)
19968c2ecf20Sopenharmony_ci{
19978c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
19988c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
19998c2ecf20Sopenharmony_ci	size_t hdr_len;
20008c2ecf20Sopenharmony_ci	size_t crypto_len;
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	if (!rxcb->is_first_msdu ||
20038c2ecf20Sopenharmony_ci	    !(rxcb->is_first_msdu && rxcb->is_last_msdu)) {
20048c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
20058c2ecf20Sopenharmony_ci		return;
20068c2ecf20Sopenharmony_ci	}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	skb_trim(msdu, msdu->len - FCS_LEN);
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	if (!decrypted)
20118c2ecf20Sopenharmony_ci		return;
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	hdr = (void *)msdu->data;
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	/* Tail */
20168c2ecf20Sopenharmony_ci	if (status->flag & RX_FLAG_IV_STRIPPED) {
20178c2ecf20Sopenharmony_ci		skb_trim(msdu, msdu->len -
20188c2ecf20Sopenharmony_ci			 ath11k_dp_rx_crypto_mic_len(ar, enctype));
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci		skb_trim(msdu, msdu->len -
20218c2ecf20Sopenharmony_ci			 ath11k_dp_rx_crypto_icv_len(ar, enctype));
20228c2ecf20Sopenharmony_ci	} else {
20238c2ecf20Sopenharmony_ci		/* MIC */
20248c2ecf20Sopenharmony_ci		if (status->flag & RX_FLAG_MIC_STRIPPED)
20258c2ecf20Sopenharmony_ci			skb_trim(msdu, msdu->len -
20268c2ecf20Sopenharmony_ci				 ath11k_dp_rx_crypto_mic_len(ar, enctype));
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci		/* ICV */
20298c2ecf20Sopenharmony_ci		if (status->flag & RX_FLAG_ICV_STRIPPED)
20308c2ecf20Sopenharmony_ci			skb_trim(msdu, msdu->len -
20318c2ecf20Sopenharmony_ci				 ath11k_dp_rx_crypto_icv_len(ar, enctype));
20328c2ecf20Sopenharmony_ci	}
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci	/* MMIC */
20358c2ecf20Sopenharmony_ci	if ((status->flag & RX_FLAG_MMIC_STRIPPED) &&
20368c2ecf20Sopenharmony_ci	    !ieee80211_has_morefrags(hdr->frame_control) &&
20378c2ecf20Sopenharmony_ci	    enctype == HAL_ENCRYPT_TYPE_TKIP_MIC)
20388c2ecf20Sopenharmony_ci		skb_trim(msdu, msdu->len - IEEE80211_CCMP_MIC_LEN);
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	/* Head */
20418c2ecf20Sopenharmony_ci	if (status->flag & RX_FLAG_IV_STRIPPED) {
20428c2ecf20Sopenharmony_ci		hdr_len = ieee80211_hdrlen(hdr->frame_control);
20438c2ecf20Sopenharmony_ci		crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype);
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci		memmove((void *)msdu->data + crypto_len,
20468c2ecf20Sopenharmony_ci			(void *)msdu->data, hdr_len);
20478c2ecf20Sopenharmony_ci		skb_pull(msdu, crypto_len);
20488c2ecf20Sopenharmony_ci	}
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_cistatic void *ath11k_dp_rx_h_find_rfc1042(struct ath11k *ar,
20528c2ecf20Sopenharmony_ci					 struct sk_buff *msdu,
20538c2ecf20Sopenharmony_ci					 enum hal_encrypt_type enctype)
20548c2ecf20Sopenharmony_ci{
20558c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
20568c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
20578c2ecf20Sopenharmony_ci	size_t hdr_len, crypto_len;
20588c2ecf20Sopenharmony_ci	void *rfc1042;
20598c2ecf20Sopenharmony_ci	bool is_amsdu;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	is_amsdu = !(rxcb->is_first_msdu && rxcb->is_last_msdu);
20628c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)ath11k_dp_rx_h_80211_hdr(rxcb->rx_desc);
20638c2ecf20Sopenharmony_ci	rfc1042 = hdr;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	if (rxcb->is_first_msdu) {
20668c2ecf20Sopenharmony_ci		hdr_len = ieee80211_hdrlen(hdr->frame_control);
20678c2ecf20Sopenharmony_ci		crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype);
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_ci		rfc1042 += hdr_len + crypto_len;
20708c2ecf20Sopenharmony_ci	}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	if (is_amsdu)
20738c2ecf20Sopenharmony_ci		rfc1042 += sizeof(struct ath11k_dp_amsdu_subframe_hdr);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	return rfc1042;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar,
20798c2ecf20Sopenharmony_ci				       struct sk_buff *msdu,
20808c2ecf20Sopenharmony_ci				       u8 *first_hdr,
20818c2ecf20Sopenharmony_ci				       enum hal_encrypt_type enctype,
20828c2ecf20Sopenharmony_ci				       struct ieee80211_rx_status *status)
20838c2ecf20Sopenharmony_ci{
20848c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
20858c2ecf20Sopenharmony_ci	struct ethhdr *eth;
20868c2ecf20Sopenharmony_ci	size_t hdr_len;
20878c2ecf20Sopenharmony_ci	u8 da[ETH_ALEN];
20888c2ecf20Sopenharmony_ci	u8 sa[ETH_ALEN];
20898c2ecf20Sopenharmony_ci	void *rfc1042;
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci	rfc1042 = ath11k_dp_rx_h_find_rfc1042(ar, msdu, enctype);
20928c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!rfc1042))
20938c2ecf20Sopenharmony_ci		return;
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	/* pull decapped header and copy SA & DA */
20968c2ecf20Sopenharmony_ci	eth = (struct ethhdr *)msdu->data;
20978c2ecf20Sopenharmony_ci	ether_addr_copy(da, eth->h_dest);
20988c2ecf20Sopenharmony_ci	ether_addr_copy(sa, eth->h_source);
20998c2ecf20Sopenharmony_ci	skb_pull(msdu, sizeof(struct ethhdr));
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	/* push rfc1042/llc/snap */
21028c2ecf20Sopenharmony_ci	memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), rfc1042,
21038c2ecf20Sopenharmony_ci	       sizeof(struct ath11k_dp_rfc1042_hdr));
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	/* push original 802.11 header */
21068c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)first_hdr;
21078c2ecf20Sopenharmony_ci	hdr_len = ieee80211_hdrlen(hdr->frame_control);
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
21108c2ecf20Sopenharmony_ci		memcpy(skb_push(msdu,
21118c2ecf20Sopenharmony_ci				ath11k_dp_rx_crypto_param_len(ar, enctype)),
21128c2ecf20Sopenharmony_ci		       (void *)hdr + hdr_len,
21138c2ecf20Sopenharmony_ci		       ath11k_dp_rx_crypto_param_len(ar, enctype));
21148c2ecf20Sopenharmony_ci	}
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	/* original 802.11 header has a different DA and in
21198c2ecf20Sopenharmony_ci	 * case of 4addr it may also have different SA
21208c2ecf20Sopenharmony_ci	 */
21218c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)msdu->data;
21228c2ecf20Sopenharmony_ci	ether_addr_copy(ieee80211_get_DA(hdr), da);
21238c2ecf20Sopenharmony_ci	ether_addr_copy(ieee80211_get_SA(hdr), sa);
21248c2ecf20Sopenharmony_ci}
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap(struct ath11k *ar, struct sk_buff *msdu,
21278c2ecf20Sopenharmony_ci				   struct hal_rx_desc *rx_desc,
21288c2ecf20Sopenharmony_ci				   enum hal_encrypt_type enctype,
21298c2ecf20Sopenharmony_ci				   struct ieee80211_rx_status *status,
21308c2ecf20Sopenharmony_ci				   bool decrypted)
21318c2ecf20Sopenharmony_ci{
21328c2ecf20Sopenharmony_ci	u8 *first_hdr;
21338c2ecf20Sopenharmony_ci	u8 decap;
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	first_hdr = ath11k_dp_rx_h_80211_hdr(rx_desc);
21368c2ecf20Sopenharmony_ci	decap = ath11k_dp_rx_h_msdu_start_decap_type(rx_desc);
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	switch (decap) {
21398c2ecf20Sopenharmony_ci	case DP_RX_DECAP_TYPE_NATIVE_WIFI:
21408c2ecf20Sopenharmony_ci		ath11k_dp_rx_h_undecap_nwifi(ar, msdu, first_hdr,
21418c2ecf20Sopenharmony_ci					     enctype, status);
21428c2ecf20Sopenharmony_ci		break;
21438c2ecf20Sopenharmony_ci	case DP_RX_DECAP_TYPE_RAW:
21448c2ecf20Sopenharmony_ci		ath11k_dp_rx_h_undecap_raw(ar, msdu, enctype, status,
21458c2ecf20Sopenharmony_ci					   decrypted);
21468c2ecf20Sopenharmony_ci		break;
21478c2ecf20Sopenharmony_ci	case DP_RX_DECAP_TYPE_ETHERNET2_DIX:
21488c2ecf20Sopenharmony_ci		/* TODO undecap support for middle/last msdu's of amsdu */
21498c2ecf20Sopenharmony_ci		ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr,
21508c2ecf20Sopenharmony_ci					   enctype, status);
21518c2ecf20Sopenharmony_ci		break;
21528c2ecf20Sopenharmony_ci	case DP_RX_DECAP_TYPE_8023:
21538c2ecf20Sopenharmony_ci		/* TODO: Handle undecap for these formats */
21548c2ecf20Sopenharmony_ci		break;
21558c2ecf20Sopenharmony_ci	}
21568c2ecf20Sopenharmony_ci}
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_mpdu(struct ath11k *ar,
21598c2ecf20Sopenharmony_ci				struct sk_buff *msdu,
21608c2ecf20Sopenharmony_ci				struct hal_rx_desc *rx_desc,
21618c2ecf20Sopenharmony_ci				struct ieee80211_rx_status *rx_status)
21628c2ecf20Sopenharmony_ci{
21638c2ecf20Sopenharmony_ci	bool  fill_crypto_hdr, mcast;
21648c2ecf20Sopenharmony_ci	enum hal_encrypt_type enctype;
21658c2ecf20Sopenharmony_ci	bool is_decrypted = false;
21668c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
21678c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
21688c2ecf20Sopenharmony_ci	u32 err_bitmap;
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)msdu->data;
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	/* PN for multicast packets will be checked in mac80211 */
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	mcast = is_multicast_ether_addr(hdr->addr1);
21758c2ecf20Sopenharmony_ci	fill_crypto_hdr = mcast;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->ab->base_lock);
21788c2ecf20Sopenharmony_ci	peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr2);
21798c2ecf20Sopenharmony_ci	if (peer) {
21808c2ecf20Sopenharmony_ci		if (mcast)
21818c2ecf20Sopenharmony_ci			enctype = peer->sec_type_grp;
21828c2ecf20Sopenharmony_ci		else
21838c2ecf20Sopenharmony_ci			enctype = peer->sec_type;
21848c2ecf20Sopenharmony_ci	} else {
21858c2ecf20Sopenharmony_ci		enctype = HAL_ENCRYPT_TYPE_OPEN;
21868c2ecf20Sopenharmony_ci	}
21878c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->ab->base_lock);
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_desc);
21908c2ecf20Sopenharmony_ci	if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap)
21918c2ecf20Sopenharmony_ci		is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc);
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	/* Clear per-MPDU flags while leaving per-PPDU flags intact */
21948c2ecf20Sopenharmony_ci	rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |
21958c2ecf20Sopenharmony_ci			     RX_FLAG_MMIC_ERROR |
21968c2ecf20Sopenharmony_ci			     RX_FLAG_DECRYPTED |
21978c2ecf20Sopenharmony_ci			     RX_FLAG_IV_STRIPPED |
21988c2ecf20Sopenharmony_ci			     RX_FLAG_MMIC_STRIPPED);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	if (err_bitmap & DP_RX_MPDU_ERR_FCS)
22018c2ecf20Sopenharmony_ci		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
22028c2ecf20Sopenharmony_ci	if (err_bitmap & DP_RX_MPDU_ERR_TKIP_MIC)
22038c2ecf20Sopenharmony_ci		rx_status->flag |= RX_FLAG_MMIC_ERROR;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	if (is_decrypted) {
22068c2ecf20Sopenharmony_ci		rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci		if (fill_crypto_hdr)
22098c2ecf20Sopenharmony_ci			rx_status->flag |= RX_FLAG_MIC_STRIPPED |
22108c2ecf20Sopenharmony_ci					RX_FLAG_ICV_STRIPPED;
22118c2ecf20Sopenharmony_ci		else
22128c2ecf20Sopenharmony_ci			rx_status->flag |= RX_FLAG_IV_STRIPPED |
22138c2ecf20Sopenharmony_ci					   RX_FLAG_PN_VALIDATED;
22148c2ecf20Sopenharmony_ci	}
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_csum_offload(msdu);
22178c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
22188c2ecf20Sopenharmony_ci			       enctype, rx_status, is_decrypted);
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	if (!is_decrypted || fill_crypto_hdr)
22218c2ecf20Sopenharmony_ci		return;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	hdr = (void *)msdu->data;
22248c2ecf20Sopenharmony_ci	hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
22258c2ecf20Sopenharmony_ci}
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
22288c2ecf20Sopenharmony_ci				struct ieee80211_rx_status *rx_status)
22298c2ecf20Sopenharmony_ci{
22308c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
22318c2ecf20Sopenharmony_ci	enum rx_msdu_start_pkt_type pkt_type;
22328c2ecf20Sopenharmony_ci	u8 bw;
22338c2ecf20Sopenharmony_ci	u8 rate_mcs, nss;
22348c2ecf20Sopenharmony_ci	u8 sgi;
22358c2ecf20Sopenharmony_ci	bool is_cck;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(rx_desc);
22388c2ecf20Sopenharmony_ci	bw = ath11k_dp_rx_h_msdu_start_rx_bw(rx_desc);
22398c2ecf20Sopenharmony_ci	rate_mcs = ath11k_dp_rx_h_msdu_start_rate_mcs(rx_desc);
22408c2ecf20Sopenharmony_ci	nss = ath11k_dp_rx_h_msdu_start_nss(rx_desc);
22418c2ecf20Sopenharmony_ci	sgi = ath11k_dp_rx_h_msdu_start_sgi(rx_desc);
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	switch (pkt_type) {
22448c2ecf20Sopenharmony_ci	case RX_MSDU_START_PKT_TYPE_11A:
22458c2ecf20Sopenharmony_ci	case RX_MSDU_START_PKT_TYPE_11B:
22468c2ecf20Sopenharmony_ci		is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B);
22478c2ecf20Sopenharmony_ci		sband = &ar->mac.sbands[rx_status->band];
22488c2ecf20Sopenharmony_ci		rx_status->rate_idx = ath11k_mac_hw_rate_to_idx(sband, rate_mcs,
22498c2ecf20Sopenharmony_ci								is_cck);
22508c2ecf20Sopenharmony_ci		break;
22518c2ecf20Sopenharmony_ci	case RX_MSDU_START_PKT_TYPE_11N:
22528c2ecf20Sopenharmony_ci		rx_status->encoding = RX_ENC_HT;
22538c2ecf20Sopenharmony_ci		if (rate_mcs > ATH11K_HT_MCS_MAX) {
22548c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
22558c2ecf20Sopenharmony_ci				    "Received with invalid mcs in HT mode %d\n",
22568c2ecf20Sopenharmony_ci				     rate_mcs);
22578c2ecf20Sopenharmony_ci			break;
22588c2ecf20Sopenharmony_ci		}
22598c2ecf20Sopenharmony_ci		rx_status->rate_idx = rate_mcs + (8 * (nss - 1));
22608c2ecf20Sopenharmony_ci		if (sgi)
22618c2ecf20Sopenharmony_ci			rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
22628c2ecf20Sopenharmony_ci		rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw);
22638c2ecf20Sopenharmony_ci		break;
22648c2ecf20Sopenharmony_ci	case RX_MSDU_START_PKT_TYPE_11AC:
22658c2ecf20Sopenharmony_ci		rx_status->encoding = RX_ENC_VHT;
22668c2ecf20Sopenharmony_ci		rx_status->rate_idx = rate_mcs;
22678c2ecf20Sopenharmony_ci		if (rate_mcs > ATH11K_VHT_MCS_MAX) {
22688c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
22698c2ecf20Sopenharmony_ci				    "Received with invalid mcs in VHT mode %d\n",
22708c2ecf20Sopenharmony_ci				     rate_mcs);
22718c2ecf20Sopenharmony_ci			break;
22728c2ecf20Sopenharmony_ci		}
22738c2ecf20Sopenharmony_ci		rx_status->nss = nss;
22748c2ecf20Sopenharmony_ci		if (sgi)
22758c2ecf20Sopenharmony_ci			rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
22768c2ecf20Sopenharmony_ci		rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw);
22778c2ecf20Sopenharmony_ci		break;
22788c2ecf20Sopenharmony_ci	case RX_MSDU_START_PKT_TYPE_11AX:
22798c2ecf20Sopenharmony_ci		rx_status->rate_idx = rate_mcs;
22808c2ecf20Sopenharmony_ci		if (rate_mcs > ATH11K_HE_MCS_MAX) {
22818c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
22828c2ecf20Sopenharmony_ci				    "Received with invalid mcs in HE mode %d\n",
22838c2ecf20Sopenharmony_ci				    rate_mcs);
22848c2ecf20Sopenharmony_ci			break;
22858c2ecf20Sopenharmony_ci		}
22868c2ecf20Sopenharmony_ci		rx_status->encoding = RX_ENC_HE;
22878c2ecf20Sopenharmony_ci		rx_status->nss = nss;
22888c2ecf20Sopenharmony_ci		rx_status->he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi);
22898c2ecf20Sopenharmony_ci		rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw);
22908c2ecf20Sopenharmony_ci		break;
22918c2ecf20Sopenharmony_ci	}
22928c2ecf20Sopenharmony_ci}
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
22958c2ecf20Sopenharmony_ci				struct ieee80211_rx_status *rx_status)
22968c2ecf20Sopenharmony_ci{
22978c2ecf20Sopenharmony_ci	u8 channel_num;
22988c2ecf20Sopenharmony_ci	u32 center_freq;
22998c2ecf20Sopenharmony_ci	struct ieee80211_channel *channel;
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	rx_status->freq = 0;
23028c2ecf20Sopenharmony_ci	rx_status->rate_idx = 0;
23038c2ecf20Sopenharmony_ci	rx_status->nss = 0;
23048c2ecf20Sopenharmony_ci	rx_status->encoding = RX_ENC_LEGACY;
23058c2ecf20Sopenharmony_ci	rx_status->bw = RATE_INFO_BW_20;
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	channel_num = ath11k_dp_rx_h_msdu_start_freq(rx_desc);
23108c2ecf20Sopenharmony_ci	center_freq = ath11k_dp_rx_h_msdu_start_freq(rx_desc) >> 16;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	if (center_freq >= ATH11K_MIN_6G_FREQ &&
23138c2ecf20Sopenharmony_ci	    center_freq <= ATH11K_MAX_6G_FREQ) {
23148c2ecf20Sopenharmony_ci		rx_status->band = NL80211_BAND_6GHZ;
23158c2ecf20Sopenharmony_ci		rx_status->freq = center_freq;
23168c2ecf20Sopenharmony_ci	} else if (channel_num >= 1 && channel_num <= 14) {
23178c2ecf20Sopenharmony_ci		rx_status->band = NL80211_BAND_2GHZ;
23188c2ecf20Sopenharmony_ci	} else if (channel_num >= 36 && channel_num <= 173) {
23198c2ecf20Sopenharmony_ci		rx_status->band = NL80211_BAND_5GHZ;
23208c2ecf20Sopenharmony_ci	} else {
23218c2ecf20Sopenharmony_ci		spin_lock_bh(&ar->data_lock);
23228c2ecf20Sopenharmony_ci		channel = ar->rx_channel;
23238c2ecf20Sopenharmony_ci		if (channel) {
23248c2ecf20Sopenharmony_ci			rx_status->band = channel->band;
23258c2ecf20Sopenharmony_ci			channel_num =
23268c2ecf20Sopenharmony_ci				ieee80211_frequency_to_channel(channel->center_freq);
23278c2ecf20Sopenharmony_ci		}
23288c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->data_lock);
23298c2ecf20Sopenharmony_ci		ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "rx_desc: ",
23308c2ecf20Sopenharmony_ci				rx_desc, sizeof(struct hal_rx_desc));
23318c2ecf20Sopenharmony_ci	}
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	if (rx_status->band != NL80211_BAND_6GHZ)
23348c2ecf20Sopenharmony_ci		rx_status->freq = ieee80211_channel_to_frequency(channel_num,
23358c2ecf20Sopenharmony_ci								 rx_status->band);
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_rate(ar, rx_desc, rx_status);
23388c2ecf20Sopenharmony_ci}
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_cistatic char *ath11k_print_get_tid(struct ieee80211_hdr *hdr, char *out,
23418c2ecf20Sopenharmony_ci				  size_t size)
23428c2ecf20Sopenharmony_ci{
23438c2ecf20Sopenharmony_ci	u8 *qc;
23448c2ecf20Sopenharmony_ci	int tid;
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	if (!ieee80211_is_data_qos(hdr->frame_control))
23478c2ecf20Sopenharmony_ci		return "";
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	qc = ieee80211_get_qos_ctl(hdr);
23508c2ecf20Sopenharmony_ci	tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
23518c2ecf20Sopenharmony_ci	snprintf(out, size, "tid %d", tid);
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	return out;
23548c2ecf20Sopenharmony_ci}
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *napi,
23578c2ecf20Sopenharmony_ci				      struct sk_buff *msdu)
23588c2ecf20Sopenharmony_ci{
23598c2ecf20Sopenharmony_ci	static const struct ieee80211_radiotap_he known = {
23608c2ecf20Sopenharmony_ci		.data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
23618c2ecf20Sopenharmony_ci				     IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN),
23628c2ecf20Sopenharmony_ci		.data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN),
23638c2ecf20Sopenharmony_ci	};
23648c2ecf20Sopenharmony_ci	struct ieee80211_rx_status *status;
23658c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
23668c2ecf20Sopenharmony_ci	struct ieee80211_radiotap_he *he = NULL;
23678c2ecf20Sopenharmony_ci	char tid[32];
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	status = IEEE80211_SKB_RXCB(msdu);
23708c2ecf20Sopenharmony_ci	if (status->encoding == RX_ENC_HE) {
23718c2ecf20Sopenharmony_ci		he = skb_push(msdu, sizeof(known));
23728c2ecf20Sopenharmony_ci		memcpy(he, &known, sizeof(known));
23738c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_RADIOTAP_HE;
23748c2ecf20Sopenharmony_ci	}
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
23778c2ecf20Sopenharmony_ci		   "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
23788c2ecf20Sopenharmony_ci		   msdu,
23798c2ecf20Sopenharmony_ci		   msdu->len,
23808c2ecf20Sopenharmony_ci		   ieee80211_get_SA(hdr),
23818c2ecf20Sopenharmony_ci		   ath11k_print_get_tid(hdr, tid, sizeof(tid)),
23828c2ecf20Sopenharmony_ci		   is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
23838c2ecf20Sopenharmony_ci							"mcast" : "ucast",
23848c2ecf20Sopenharmony_ci		   (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
23858c2ecf20Sopenharmony_ci		   (status->encoding == RX_ENC_LEGACY) ? "legacy" : "",
23868c2ecf20Sopenharmony_ci		   (status->encoding == RX_ENC_HT) ? "ht" : "",
23878c2ecf20Sopenharmony_ci		   (status->encoding == RX_ENC_VHT) ? "vht" : "",
23888c2ecf20Sopenharmony_ci		   (status->encoding == RX_ENC_HE) ? "he" : "",
23898c2ecf20Sopenharmony_ci		   (status->bw == RATE_INFO_BW_40) ? "40" : "",
23908c2ecf20Sopenharmony_ci		   (status->bw == RATE_INFO_BW_80) ? "80" : "",
23918c2ecf20Sopenharmony_ci		   (status->bw == RATE_INFO_BW_160) ? "160" : "",
23928c2ecf20Sopenharmony_ci		   status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "",
23938c2ecf20Sopenharmony_ci		   status->rate_idx,
23948c2ecf20Sopenharmony_ci		   status->nss,
23958c2ecf20Sopenharmony_ci		   status->freq,
23968c2ecf20Sopenharmony_ci		   status->band, status->flag,
23978c2ecf20Sopenharmony_ci		   !!(status->flag & RX_FLAG_FAILED_FCS_CRC),
23988c2ecf20Sopenharmony_ci		   !!(status->flag & RX_FLAG_MMIC_ERROR),
23998c2ecf20Sopenharmony_ci		   !!(status->flag & RX_FLAG_AMSDU_MORE));
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	ath11k_dbg_dump(ar->ab, ATH11K_DBG_DP_RX, NULL, "dp rx msdu: ",
24028c2ecf20Sopenharmony_ci			msdu->data, msdu->len);
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	/* TODO: trace rx packet */
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	ieee80211_rx_napi(ar->hw, NULL, msdu, napi);
24078c2ecf20Sopenharmony_ci}
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_process_msdu(struct ath11k *ar,
24108c2ecf20Sopenharmony_ci				     struct sk_buff *msdu,
24118c2ecf20Sopenharmony_ci				     struct sk_buff_head *msdu_list)
24128c2ecf20Sopenharmony_ci{
24138c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc, *lrx_desc;
24148c2ecf20Sopenharmony_ci	struct ieee80211_rx_status rx_status = {0};
24158c2ecf20Sopenharmony_ci	struct ieee80211_rx_status *status;
24168c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
24178c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
24188c2ecf20Sopenharmony_ci	struct sk_buff *last_buf;
24198c2ecf20Sopenharmony_ci	u8 l3_pad_bytes;
24208c2ecf20Sopenharmony_ci	u8 *hdr_status;
24218c2ecf20Sopenharmony_ci	u16 msdu_len;
24228c2ecf20Sopenharmony_ci	int ret;
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	last_buf = ath11k_dp_rx_get_msdu_last_buf(msdu_list, msdu);
24258c2ecf20Sopenharmony_ci	if (!last_buf) {
24268c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
24278c2ecf20Sopenharmony_ci			    "No valid Rx buffer to access Atten/MSDU_END/MPDU_END tlvs\n");
24288c2ecf20Sopenharmony_ci		ret = -EIO;
24298c2ecf20Sopenharmony_ci		goto free_out;
24308c2ecf20Sopenharmony_ci	}
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	rx_desc = (struct hal_rx_desc *)msdu->data;
24338c2ecf20Sopenharmony_ci	lrx_desc = (struct hal_rx_desc *)last_buf->data;
24348c2ecf20Sopenharmony_ci	if (!ath11k_dp_rx_h_attn_msdu_done(lrx_desc)) {
24358c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "msdu_done bit in attention is not set\n");
24368c2ecf20Sopenharmony_ci		ret = -EIO;
24378c2ecf20Sopenharmony_ci		goto free_out;
24388c2ecf20Sopenharmony_ci	}
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	rxcb = ATH11K_SKB_RXCB(msdu);
24418c2ecf20Sopenharmony_ci	rxcb->rx_desc = rx_desc;
24428c2ecf20Sopenharmony_ci	msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc);
24438c2ecf20Sopenharmony_ci	l3_pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(lrx_desc);
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	if (rxcb->is_frag) {
24468c2ecf20Sopenharmony_ci		skb_pull(msdu, HAL_RX_DESC_SIZE);
24478c2ecf20Sopenharmony_ci	} else if (!rxcb->is_continuation) {
24488c2ecf20Sopenharmony_ci		if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) {
24498c2ecf20Sopenharmony_ci			hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc);
24508c2ecf20Sopenharmony_ci			ret = -EINVAL;
24518c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "invalid msdu len %u\n", msdu_len);
24528c2ecf20Sopenharmony_ci			ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status,
24538c2ecf20Sopenharmony_ci					sizeof(struct ieee80211_hdr));
24548c2ecf20Sopenharmony_ci			ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc,
24558c2ecf20Sopenharmony_ci					sizeof(struct hal_rx_desc));
24568c2ecf20Sopenharmony_ci			goto free_out;
24578c2ecf20Sopenharmony_ci		}
24588c2ecf20Sopenharmony_ci		skb_put(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes + msdu_len);
24598c2ecf20Sopenharmony_ci		skb_pull(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes);
24608c2ecf20Sopenharmony_ci	} else {
24618c2ecf20Sopenharmony_ci		ret = ath11k_dp_rx_msdu_coalesce(ar, msdu_list,
24628c2ecf20Sopenharmony_ci						 msdu, last_buf,
24638c2ecf20Sopenharmony_ci						 l3_pad_bytes, msdu_len);
24648c2ecf20Sopenharmony_ci		if (ret) {
24658c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
24668c2ecf20Sopenharmony_ci				    "failed to coalesce msdu rx buffer%d\n", ret);
24678c2ecf20Sopenharmony_ci			goto free_out;
24688c2ecf20Sopenharmony_ci		}
24698c2ecf20Sopenharmony_ci	}
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)msdu->data;
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci	/* Process only data frames */
24748c2ecf20Sopenharmony_ci	if (!ieee80211_is_data(hdr->frame_control))
24758c2ecf20Sopenharmony_ci		return -EINVAL;
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_ppdu(ar, rx_desc, &rx_status);
24788c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, &rx_status);
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	rx_status.flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED;
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	status = IEEE80211_SKB_RXCB(msdu);
24838c2ecf20Sopenharmony_ci	*status = rx_status;
24848c2ecf20Sopenharmony_ci	return 0;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_cifree_out:
24878c2ecf20Sopenharmony_ci	return ret;
24888c2ecf20Sopenharmony_ci}
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab,
24918c2ecf20Sopenharmony_ci						  struct napi_struct *napi,
24928c2ecf20Sopenharmony_ci						  struct sk_buff_head *msdu_list,
24938c2ecf20Sopenharmony_ci						  int *quota, int ring_id)
24948c2ecf20Sopenharmony_ci{
24958c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
24968c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
24978c2ecf20Sopenharmony_ci	struct ath11k *ar;
24988c2ecf20Sopenharmony_ci	u8 mac_id;
24998c2ecf20Sopenharmony_ci	int ret;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci	if (skb_queue_empty(msdu_list))
25028c2ecf20Sopenharmony_ci		return;
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	rcu_read_lock();
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci	while (*quota && (msdu = __skb_dequeue(msdu_list))) {
25078c2ecf20Sopenharmony_ci		rxcb = ATH11K_SKB_RXCB(msdu);
25088c2ecf20Sopenharmony_ci		mac_id = rxcb->mac_id;
25098c2ecf20Sopenharmony_ci		ar = ab->pdevs[mac_id].ar;
25108c2ecf20Sopenharmony_ci		if (!rcu_dereference(ab->pdevs_active[mac_id])) {
25118c2ecf20Sopenharmony_ci			dev_kfree_skb_any(msdu);
25128c2ecf20Sopenharmony_ci			continue;
25138c2ecf20Sopenharmony_ci		}
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci		if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
25168c2ecf20Sopenharmony_ci			dev_kfree_skb_any(msdu);
25178c2ecf20Sopenharmony_ci			continue;
25188c2ecf20Sopenharmony_ci		}
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci		ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list);
25218c2ecf20Sopenharmony_ci		if (ret) {
25228c2ecf20Sopenharmony_ci			ath11k_dbg(ab, ATH11K_DBG_DATA,
25238c2ecf20Sopenharmony_ci				   "Unable to process msdu %d", ret);
25248c2ecf20Sopenharmony_ci			dev_kfree_skb_any(msdu);
25258c2ecf20Sopenharmony_ci			continue;
25268c2ecf20Sopenharmony_ci		}
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci		ath11k_dp_rx_deliver_msdu(ar, napi, msdu);
25298c2ecf20Sopenharmony_ci		(*quota)--;
25308c2ecf20Sopenharmony_ci	}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	rcu_read_unlock();
25338c2ecf20Sopenharmony_ci}
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ciint ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id,
25368c2ecf20Sopenharmony_ci			 struct napi_struct *napi, int budget)
25378c2ecf20Sopenharmony_ci{
25388c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
25398c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring;
25408c2ecf20Sopenharmony_ci	int num_buffs_reaped[MAX_RADIOS] = {0};
25418c2ecf20Sopenharmony_ci	struct sk_buff_head msdu_list;
25428c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
25438c2ecf20Sopenharmony_ci	int total_msdu_reaped = 0;
25448c2ecf20Sopenharmony_ci	struct hal_srng *srng;
25458c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
25468c2ecf20Sopenharmony_ci	int quota = budget;
25478c2ecf20Sopenharmony_ci	bool done = false;
25488c2ecf20Sopenharmony_ci	int buf_id, mac_id;
25498c2ecf20Sopenharmony_ci	struct ath11k *ar;
25508c2ecf20Sopenharmony_ci	u32 *rx_desc;
25518c2ecf20Sopenharmony_ci	int i;
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	__skb_queue_head_init(&msdu_list);
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id];
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_citry_again:
25628c2ecf20Sopenharmony_ci	while ((rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
25638c2ecf20Sopenharmony_ci		struct hal_reo_dest_ring desc = *(struct hal_reo_dest_ring *)rx_desc;
25648c2ecf20Sopenharmony_ci		enum hal_reo_dest_ring_push_reason push_reason;
25658c2ecf20Sopenharmony_ci		u32 cookie;
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci		cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
25688c2ecf20Sopenharmony_ci				   desc.buf_addr_info.info1);
25698c2ecf20Sopenharmony_ci		buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
25708c2ecf20Sopenharmony_ci				   cookie);
25718c2ecf20Sopenharmony_ci		mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie);
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci		if (unlikely(buf_id == 0))
25748c2ecf20Sopenharmony_ci			continue;
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci		ar = ab->pdevs[mac_id].ar;
25778c2ecf20Sopenharmony_ci		rx_ring = &ar->dp.rx_refill_buf_ring;
25788c2ecf20Sopenharmony_ci		spin_lock_bh(&rx_ring->idr_lock);
25798c2ecf20Sopenharmony_ci		msdu = idr_find(&rx_ring->bufs_idr, buf_id);
25808c2ecf20Sopenharmony_ci		if (!msdu) {
25818c2ecf20Sopenharmony_ci			ath11k_warn(ab, "frame rx with invalid buf_id %d\n",
25828c2ecf20Sopenharmony_ci				    buf_id);
25838c2ecf20Sopenharmony_ci			spin_unlock_bh(&rx_ring->idr_lock);
25848c2ecf20Sopenharmony_ci			continue;
25858c2ecf20Sopenharmony_ci		}
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci		idr_remove(&rx_ring->bufs_idr, buf_id);
25888c2ecf20Sopenharmony_ci		spin_unlock_bh(&rx_ring->idr_lock);
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci		rxcb = ATH11K_SKB_RXCB(msdu);
25918c2ecf20Sopenharmony_ci		dma_unmap_single(ab->dev, rxcb->paddr,
25928c2ecf20Sopenharmony_ci				 msdu->len + skb_tailroom(msdu),
25938c2ecf20Sopenharmony_ci				 DMA_FROM_DEVICE);
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci		num_buffs_reaped[mac_id]++;
25968c2ecf20Sopenharmony_ci		total_msdu_reaped++;
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci		push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
25998c2ecf20Sopenharmony_ci					desc.info0);
26008c2ecf20Sopenharmony_ci		if (push_reason !=
26018c2ecf20Sopenharmony_ci		    HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
26028c2ecf20Sopenharmony_ci			dev_kfree_skb_any(msdu);
26038c2ecf20Sopenharmony_ci			ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++;
26048c2ecf20Sopenharmony_ci			continue;
26058c2ecf20Sopenharmony_ci		}
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci		rxcb->is_first_msdu = !!(desc.rx_msdu_info.info0 &
26088c2ecf20Sopenharmony_ci					 RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
26098c2ecf20Sopenharmony_ci		rxcb->is_last_msdu = !!(desc.rx_msdu_info.info0 &
26108c2ecf20Sopenharmony_ci					RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
26118c2ecf20Sopenharmony_ci		rxcb->is_continuation = !!(desc.rx_msdu_info.info0 &
26128c2ecf20Sopenharmony_ci					   RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
26138c2ecf20Sopenharmony_ci		rxcb->mac_id = mac_id;
26148c2ecf20Sopenharmony_ci		rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM,
26158c2ecf20Sopenharmony_ci				      desc.info0);
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci		__skb_queue_tail(&msdu_list, msdu);
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci		if (total_msdu_reaped >= quota && !rxcb->is_continuation) {
26208c2ecf20Sopenharmony_ci			done = true;
26218c2ecf20Sopenharmony_ci			break;
26228c2ecf20Sopenharmony_ci		}
26238c2ecf20Sopenharmony_ci	}
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	/* Hw might have updated the head pointer after we cached it.
26268c2ecf20Sopenharmony_ci	 * In this case, even though there are entries in the ring we'll
26278c2ecf20Sopenharmony_ci	 * get rx_desc NULL. Give the read another try with updated cached
26288c2ecf20Sopenharmony_ci	 * head pointer so that we can reap complete MPDU in the current
26298c2ecf20Sopenharmony_ci	 * rx processing.
26308c2ecf20Sopenharmony_ci	 */
26318c2ecf20Sopenharmony_ci	if (!done && ath11k_hal_srng_dst_num_free(ab, srng, true)) {
26328c2ecf20Sopenharmony_ci		ath11k_hal_srng_access_end(ab, srng);
26338c2ecf20Sopenharmony_ci		goto try_again;
26348c2ecf20Sopenharmony_ci	}
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	if (!total_msdu_reaped)
26418c2ecf20Sopenharmony_ci		goto exit;
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
26448c2ecf20Sopenharmony_ci		if (!num_buffs_reaped[i])
26458c2ecf20Sopenharmony_ci			continue;
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci		ar = ab->pdevs[i].ar;
26488c2ecf20Sopenharmony_ci		rx_ring = &ar->dp.rx_refill_buf_ring;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci		ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i],
26518c2ecf20Sopenharmony_ci					   HAL_RX_BUF_RBM_SW3_BM);
26528c2ecf20Sopenharmony_ci	}
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list,
26558c2ecf20Sopenharmony_ci					      &quota, ring_id);
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ciexit:
26588c2ecf20Sopenharmony_ci	return budget - quota;
26598c2ecf20Sopenharmony_ci}
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta,
26628c2ecf20Sopenharmony_ci					   struct hal_rx_mon_ppdu_info *ppdu_info)
26638c2ecf20Sopenharmony_ci{
26648c2ecf20Sopenharmony_ci	struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
26658c2ecf20Sopenharmony_ci	u32 num_msdu;
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	if (!rx_stats)
26688c2ecf20Sopenharmony_ci		return;
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	num_msdu = ppdu_info->tcp_msdu_count + ppdu_info->tcp_ack_msdu_count +
26718c2ecf20Sopenharmony_ci		   ppdu_info->udp_msdu_count + ppdu_info->other_msdu_count;
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	rx_stats->num_msdu += num_msdu;
26748c2ecf20Sopenharmony_ci	rx_stats->tcp_msdu_count += ppdu_info->tcp_msdu_count +
26758c2ecf20Sopenharmony_ci				    ppdu_info->tcp_ack_msdu_count;
26768c2ecf20Sopenharmony_ci	rx_stats->udp_msdu_count += ppdu_info->udp_msdu_count;
26778c2ecf20Sopenharmony_ci	rx_stats->other_msdu_count += ppdu_info->other_msdu_count;
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11A ||
26808c2ecf20Sopenharmony_ci	    ppdu_info->preamble_type == HAL_RX_PREAMBLE_11B) {
26818c2ecf20Sopenharmony_ci		ppdu_info->nss = 1;
26828c2ecf20Sopenharmony_ci		ppdu_info->mcs = HAL_RX_MAX_MCS;
26838c2ecf20Sopenharmony_ci		ppdu_info->tid = IEEE80211_NUM_TIDS;
26848c2ecf20Sopenharmony_ci	}
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	if (ppdu_info->nss > 0 && ppdu_info->nss <= HAL_RX_MAX_NSS)
26878c2ecf20Sopenharmony_ci		rx_stats->nss_count[ppdu_info->nss - 1] += num_msdu;
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_ci	if (ppdu_info->mcs <= HAL_RX_MAX_MCS)
26908c2ecf20Sopenharmony_ci		rx_stats->mcs_count[ppdu_info->mcs] += num_msdu;
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	if (ppdu_info->gi < HAL_RX_GI_MAX)
26938c2ecf20Sopenharmony_ci		rx_stats->gi_count[ppdu_info->gi] += num_msdu;
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci	if (ppdu_info->bw < HAL_RX_BW_MAX)
26968c2ecf20Sopenharmony_ci		rx_stats->bw_count[ppdu_info->bw] += num_msdu;
26978c2ecf20Sopenharmony_ci
26988c2ecf20Sopenharmony_ci	if (ppdu_info->ldpc < HAL_RX_SU_MU_CODING_MAX)
26998c2ecf20Sopenharmony_ci		rx_stats->coding_count[ppdu_info->ldpc] += num_msdu;
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	if (ppdu_info->tid <= IEEE80211_NUM_TIDS)
27028c2ecf20Sopenharmony_ci		rx_stats->tid_count[ppdu_info->tid] += num_msdu;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	if (ppdu_info->preamble_type < HAL_RX_PREAMBLE_MAX)
27058c2ecf20Sopenharmony_ci		rx_stats->pream_cnt[ppdu_info->preamble_type] += num_msdu;
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	if (ppdu_info->reception_type < HAL_RX_RECEPTION_TYPE_MAX)
27088c2ecf20Sopenharmony_ci		rx_stats->reception_type[ppdu_info->reception_type] += num_msdu;
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	if (ppdu_info->is_stbc)
27118c2ecf20Sopenharmony_ci		rx_stats->stbc_count += num_msdu;
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci	if (ppdu_info->beamformed)
27148c2ecf20Sopenharmony_ci		rx_stats->beamformed_count += num_msdu;
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci	if (ppdu_info->num_mpdu_fcs_ok > 1)
27178c2ecf20Sopenharmony_ci		rx_stats->ampdu_msdu_count += num_msdu;
27188c2ecf20Sopenharmony_ci	else
27198c2ecf20Sopenharmony_ci		rx_stats->non_ampdu_msdu_count += num_msdu;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	rx_stats->num_mpdu_fcs_ok += ppdu_info->num_mpdu_fcs_ok;
27228c2ecf20Sopenharmony_ci	rx_stats->num_mpdu_fcs_err += ppdu_info->num_mpdu_fcs_err;
27238c2ecf20Sopenharmony_ci	rx_stats->dcm_count += ppdu_info->dcm;
27248c2ecf20Sopenharmony_ci	rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu;
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	arsta->rssi_comb = ppdu_info->rssi_comb;
27278c2ecf20Sopenharmony_ci	rx_stats->rx_duration += ppdu_info->rx_duration;
27288c2ecf20Sopenharmony_ci	arsta->rx_duration = rx_stats->rx_duration;
27298c2ecf20Sopenharmony_ci}
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_cistatic struct sk_buff *ath11k_dp_rx_alloc_mon_status_buf(struct ath11k_base *ab,
27328c2ecf20Sopenharmony_ci							 struct dp_rxdma_ring *rx_ring,
27338c2ecf20Sopenharmony_ci							 int *buf_id)
27348c2ecf20Sopenharmony_ci{
27358c2ecf20Sopenharmony_ci	struct sk_buff *skb;
27368c2ecf20Sopenharmony_ci	dma_addr_t paddr;
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	skb = dev_alloc_skb(DP_RX_BUFFER_SIZE +
27398c2ecf20Sopenharmony_ci			    DP_RX_BUFFER_ALIGN_SIZE);
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_ci	if (!skb)
27428c2ecf20Sopenharmony_ci		goto fail_alloc_skb;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	if (!IS_ALIGNED((unsigned long)skb->data,
27458c2ecf20Sopenharmony_ci			DP_RX_BUFFER_ALIGN_SIZE)) {
27468c2ecf20Sopenharmony_ci		skb_pull(skb, PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) -
27478c2ecf20Sopenharmony_ci			 skb->data);
27488c2ecf20Sopenharmony_ci	}
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	paddr = dma_map_single(ab->dev, skb->data,
27518c2ecf20Sopenharmony_ci			       skb->len + skb_tailroom(skb),
27528c2ecf20Sopenharmony_ci			       DMA_BIDIRECTIONAL);
27538c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(ab->dev, paddr)))
27548c2ecf20Sopenharmony_ci		goto fail_free_skb;
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_ring->idr_lock);
27578c2ecf20Sopenharmony_ci	*buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0,
27588c2ecf20Sopenharmony_ci			    rx_ring->bufs_max, GFP_ATOMIC);
27598c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_ring->idr_lock);
27608c2ecf20Sopenharmony_ci	if (*buf_id < 0)
27618c2ecf20Sopenharmony_ci		goto fail_dma_unmap;
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci	ATH11K_SKB_RXCB(skb)->paddr = paddr;
27648c2ecf20Sopenharmony_ci	return skb;
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_cifail_dma_unmap:
27678c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
27688c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
27698c2ecf20Sopenharmony_cifail_free_skb:
27708c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
27718c2ecf20Sopenharmony_cifail_alloc_skb:
27728c2ecf20Sopenharmony_ci	return NULL;
27738c2ecf20Sopenharmony_ci}
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ciint ath11k_dp_rx_mon_status_bufs_replenish(struct ath11k_base *ab, int mac_id,
27768c2ecf20Sopenharmony_ci					   struct dp_rxdma_ring *rx_ring,
27778c2ecf20Sopenharmony_ci					   int req_entries,
27788c2ecf20Sopenharmony_ci					   enum hal_rx_buf_return_buf_manager mgr)
27798c2ecf20Sopenharmony_ci{
27808c2ecf20Sopenharmony_ci	struct hal_srng *srng;
27818c2ecf20Sopenharmony_ci	u32 *desc;
27828c2ecf20Sopenharmony_ci	struct sk_buff *skb;
27838c2ecf20Sopenharmony_ci	int num_free;
27848c2ecf20Sopenharmony_ci	int num_remain;
27858c2ecf20Sopenharmony_ci	int buf_id;
27868c2ecf20Sopenharmony_ci	u32 cookie;
27878c2ecf20Sopenharmony_ci	dma_addr_t paddr;
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	req_entries = min(req_entries, rx_ring->bufs_max);
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
27948c2ecf20Sopenharmony_ci
27958c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	num_free = ath11k_hal_srng_src_num_free(ab, srng, true);
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	req_entries = min(num_free, req_entries);
28008c2ecf20Sopenharmony_ci	num_remain = req_entries;
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	while (num_remain > 0) {
28038c2ecf20Sopenharmony_ci		skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
28048c2ecf20Sopenharmony_ci							&buf_id);
28058c2ecf20Sopenharmony_ci		if (!skb)
28068c2ecf20Sopenharmony_ci			break;
28078c2ecf20Sopenharmony_ci		paddr = ATH11K_SKB_RXCB(skb)->paddr;
28088c2ecf20Sopenharmony_ci
28098c2ecf20Sopenharmony_ci		desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
28108c2ecf20Sopenharmony_ci		if (!desc)
28118c2ecf20Sopenharmony_ci			goto fail_desc_get;
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci		cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) |
28148c2ecf20Sopenharmony_ci			 FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci		num_remain--;
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci		ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr);
28198c2ecf20Sopenharmony_ci	}
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	return req_entries - num_remain;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_cifail_desc_get:
28288c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_ring->idr_lock);
28298c2ecf20Sopenharmony_ci	idr_remove(&rx_ring->bufs_idr, buf_id);
28308c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_ring->idr_lock);
28318c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
28328c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
28338c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
28348c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
28358c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci	return req_entries - num_remain;
28388c2ecf20Sopenharmony_ci}
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
28418c2ecf20Sopenharmony_ci					     int *budget, struct sk_buff_head *skb_list)
28428c2ecf20Sopenharmony_ci{
28438c2ecf20Sopenharmony_ci	struct ath11k *ar;
28448c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp;
28458c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring;
28468c2ecf20Sopenharmony_ci	struct hal_srng *srng;
28478c2ecf20Sopenharmony_ci	void *rx_mon_status_desc;
28488c2ecf20Sopenharmony_ci	struct sk_buff *skb;
28498c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
28508c2ecf20Sopenharmony_ci	struct hal_tlv_hdr *tlv;
28518c2ecf20Sopenharmony_ci	u32 cookie;
28528c2ecf20Sopenharmony_ci	int buf_id, srng_id;
28538c2ecf20Sopenharmony_ci	dma_addr_t paddr;
28548c2ecf20Sopenharmony_ci	u8 rbm;
28558c2ecf20Sopenharmony_ci	int num_buffs_reaped = 0;
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar;
28588c2ecf20Sopenharmony_ci	dp = &ar->dp;
28598c2ecf20Sopenharmony_ci	srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id);
28608c2ecf20Sopenharmony_ci	rx_ring = &dp->rx_mon_status_refill_ring[srng_id];
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
28638c2ecf20Sopenharmony_ci
28648c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
28678c2ecf20Sopenharmony_ci	while (*budget) {
28688c2ecf20Sopenharmony_ci		*budget -= 1;
28698c2ecf20Sopenharmony_ci		rx_mon_status_desc =
28708c2ecf20Sopenharmony_ci			ath11k_hal_srng_src_peek(ab, srng);
28718c2ecf20Sopenharmony_ci		if (!rx_mon_status_desc)
28728c2ecf20Sopenharmony_ci			break;
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci		ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr,
28758c2ecf20Sopenharmony_ci						&cookie, &rbm);
28768c2ecf20Sopenharmony_ci		if (paddr) {
28778c2ecf20Sopenharmony_ci			buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie);
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci			spin_lock_bh(&rx_ring->idr_lock);
28808c2ecf20Sopenharmony_ci			skb = idr_find(&rx_ring->bufs_idr, buf_id);
28818c2ecf20Sopenharmony_ci			if (!skb) {
28828c2ecf20Sopenharmony_ci				ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n",
28838c2ecf20Sopenharmony_ci					    buf_id);
28848c2ecf20Sopenharmony_ci				spin_unlock_bh(&rx_ring->idr_lock);
28858c2ecf20Sopenharmony_ci				goto move_next;
28868c2ecf20Sopenharmony_ci			}
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci			idr_remove(&rx_ring->bufs_idr, buf_id);
28898c2ecf20Sopenharmony_ci			spin_unlock_bh(&rx_ring->idr_lock);
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci			rxcb = ATH11K_SKB_RXCB(skb);
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci			dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
28948c2ecf20Sopenharmony_ci						skb->len + skb_tailroom(skb),
28958c2ecf20Sopenharmony_ci						DMA_FROM_DEVICE);
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci			dma_unmap_single(ab->dev, rxcb->paddr,
28988c2ecf20Sopenharmony_ci					 skb->len + skb_tailroom(skb),
28998c2ecf20Sopenharmony_ci					 DMA_BIDIRECTIONAL);
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci			tlv = (struct hal_tlv_hdr *)skb->data;
29028c2ecf20Sopenharmony_ci			if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) !=
29038c2ecf20Sopenharmony_ci					HAL_RX_STATUS_BUFFER_DONE) {
29048c2ecf20Sopenharmony_ci				ath11k_warn(ab, "mon status DONE not set %lx\n",
29058c2ecf20Sopenharmony_ci					    FIELD_GET(HAL_TLV_HDR_TAG,
29068c2ecf20Sopenharmony_ci						      tlv->tl));
29078c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb);
29088c2ecf20Sopenharmony_ci				goto move_next;
29098c2ecf20Sopenharmony_ci			}
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci			__skb_queue_tail(skb_list, skb);
29128c2ecf20Sopenharmony_ci		}
29138c2ecf20Sopenharmony_cimove_next:
29148c2ecf20Sopenharmony_ci		skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
29158c2ecf20Sopenharmony_ci							&buf_id);
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci		if (!skb) {
29188c2ecf20Sopenharmony_ci			ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0,
29198c2ecf20Sopenharmony_ci							HAL_RX_BUF_RBM_SW3_BM);
29208c2ecf20Sopenharmony_ci			num_buffs_reaped++;
29218c2ecf20Sopenharmony_ci			break;
29228c2ecf20Sopenharmony_ci		}
29238c2ecf20Sopenharmony_ci		rxcb = ATH11K_SKB_RXCB(skb);
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci		cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) |
29268c2ecf20Sopenharmony_ci			 FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci		ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, rxcb->paddr,
29298c2ecf20Sopenharmony_ci						cookie, HAL_RX_BUF_RBM_SW3_BM);
29308c2ecf20Sopenharmony_ci		ath11k_hal_srng_src_get_next_entry(ab, srng);
29318c2ecf20Sopenharmony_ci		num_buffs_reaped++;
29328c2ecf20Sopenharmony_ci	}
29338c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
29348c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	return num_buffs_reaped;
29378c2ecf20Sopenharmony_ci}
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_ciint ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
29408c2ecf20Sopenharmony_ci				    struct napi_struct *napi, int budget)
29418c2ecf20Sopenharmony_ci{
29428c2ecf20Sopenharmony_ci	struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id);
29438c2ecf20Sopenharmony_ci	enum hal_rx_mon_status hal_status;
29448c2ecf20Sopenharmony_ci	struct sk_buff *skb;
29458c2ecf20Sopenharmony_ci	struct sk_buff_head skb_list;
29468c2ecf20Sopenharmony_ci	struct hal_rx_mon_ppdu_info ppdu_info;
29478c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
29488c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta;
29498c2ecf20Sopenharmony_ci	int num_buffs_reaped = 0;
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	__skb_queue_head_init(&skb_list);
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci	num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget,
29548c2ecf20Sopenharmony_ci							     &skb_list);
29558c2ecf20Sopenharmony_ci	if (!num_buffs_reaped)
29568c2ecf20Sopenharmony_ci		goto exit;
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&skb_list))) {
29598c2ecf20Sopenharmony_ci		memset(&ppdu_info, 0, sizeof(ppdu_info));
29608c2ecf20Sopenharmony_ci		ppdu_info.peer_id = HAL_INVALID_PEERID;
29618c2ecf20Sopenharmony_ci
29628c2ecf20Sopenharmony_ci		if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar))
29638c2ecf20Sopenharmony_ci			trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE);
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_ci		hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb);
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci		if (ppdu_info.peer_id == HAL_INVALID_PEERID ||
29688c2ecf20Sopenharmony_ci		    hal_status != HAL_RX_MON_STATUS_PPDU_DONE) {
29698c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
29708c2ecf20Sopenharmony_ci			continue;
29718c2ecf20Sopenharmony_ci		}
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci		rcu_read_lock();
29748c2ecf20Sopenharmony_ci		spin_lock_bh(&ab->base_lock);
29758c2ecf20Sopenharmony_ci		peer = ath11k_peer_find_by_id(ab, ppdu_info.peer_id);
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ci		if (!peer || !peer->sta) {
29788c2ecf20Sopenharmony_ci			ath11k_dbg(ab, ATH11K_DBG_DATA,
29798c2ecf20Sopenharmony_ci				   "failed to find the peer with peer_id %d\n",
29808c2ecf20Sopenharmony_ci				   ppdu_info.peer_id);
29818c2ecf20Sopenharmony_ci			spin_unlock_bh(&ab->base_lock);
29828c2ecf20Sopenharmony_ci			rcu_read_unlock();
29838c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
29848c2ecf20Sopenharmony_ci			continue;
29858c2ecf20Sopenharmony_ci		}
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci		arsta = (struct ath11k_sta *)peer->sta->drv_priv;
29888c2ecf20Sopenharmony_ci		ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info);
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci		if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr))
29918c2ecf20Sopenharmony_ci			trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE);
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
29948c2ecf20Sopenharmony_ci		rcu_read_unlock();
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
29978c2ecf20Sopenharmony_ci	}
29988c2ecf20Sopenharmony_ciexit:
29998c2ecf20Sopenharmony_ci	return num_buffs_reaped;
30008c2ecf20Sopenharmony_ci}
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_frag_timer(struct timer_list *timer)
30038c2ecf20Sopenharmony_ci{
30048c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer);
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_tid->ab->base_lock);
30078c2ecf20Sopenharmony_ci	if (rx_tid->last_frag_no &&
30088c2ecf20Sopenharmony_ci	    rx_tid->rx_frag_bitmap == GENMASK(rx_tid->last_frag_no, 0)) {
30098c2ecf20Sopenharmony_ci		spin_unlock_bh(&rx_tid->ab->base_lock);
30108c2ecf20Sopenharmony_ci		return;
30118c2ecf20Sopenharmony_ci	}
30128c2ecf20Sopenharmony_ci	ath11k_dp_rx_frags_cleanup(rx_tid, true);
30138c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_tid->ab->base_lock);
30148c2ecf20Sopenharmony_ci}
30158c2ecf20Sopenharmony_ci
30168c2ecf20Sopenharmony_ciint ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id)
30178c2ecf20Sopenharmony_ci{
30188c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
30198c2ecf20Sopenharmony_ci	struct crypto_shash *tfm;
30208c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
30218c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid;
30228c2ecf20Sopenharmony_ci	int i;
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci	tfm = crypto_alloc_shash("michael_mic", 0, 0);
30258c2ecf20Sopenharmony_ci	if (IS_ERR(tfm))
30268c2ecf20Sopenharmony_ci		return PTR_ERR(tfm);
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, vdev_id, peer_mac);
30318c2ecf20Sopenharmony_ci	if (!peer) {
30328c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to find the peer to set up fragment info\n");
30338c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
30348c2ecf20Sopenharmony_ci		crypto_free_shash(tfm);
30358c2ecf20Sopenharmony_ci		return -ENOENT;
30368c2ecf20Sopenharmony_ci	}
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	for (i = 0; i <= IEEE80211_NUM_TIDS; i++) {
30398c2ecf20Sopenharmony_ci		rx_tid = &peer->rx_tid[i];
30408c2ecf20Sopenharmony_ci		rx_tid->ab = ab;
30418c2ecf20Sopenharmony_ci		timer_setup(&rx_tid->frag_timer, ath11k_dp_rx_frag_timer, 0);
30428c2ecf20Sopenharmony_ci		skb_queue_head_init(&rx_tid->rx_frags);
30438c2ecf20Sopenharmony_ci	}
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	peer->tfm_mmic = tfm;
30468c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci	return 0;
30498c2ecf20Sopenharmony_ci}
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
30528c2ecf20Sopenharmony_ci				      struct ieee80211_hdr *hdr, u8 *data,
30538c2ecf20Sopenharmony_ci				      size_t data_len, u8 *mic)
30548c2ecf20Sopenharmony_ci{
30558c2ecf20Sopenharmony_ci	SHASH_DESC_ON_STACK(desc, tfm);
30568c2ecf20Sopenharmony_ci	u8 mic_hdr[16] = {0};
30578c2ecf20Sopenharmony_ci	u8 tid = 0;
30588c2ecf20Sopenharmony_ci	int ret;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci	if (!tfm)
30618c2ecf20Sopenharmony_ci		return -EINVAL;
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	desc->tfm = tfm;
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci	ret = crypto_shash_setkey(tfm, key, 8);
30668c2ecf20Sopenharmony_ci	if (ret)
30678c2ecf20Sopenharmony_ci		goto out;
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci	ret = crypto_shash_init(desc);
30708c2ecf20Sopenharmony_ci	if (ret)
30718c2ecf20Sopenharmony_ci		goto out;
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	/* TKIP MIC header */
30748c2ecf20Sopenharmony_ci	memcpy(mic_hdr, ieee80211_get_DA(hdr), ETH_ALEN);
30758c2ecf20Sopenharmony_ci	memcpy(mic_hdr + ETH_ALEN, ieee80211_get_SA(hdr), ETH_ALEN);
30768c2ecf20Sopenharmony_ci	if (ieee80211_is_data_qos(hdr->frame_control))
30778c2ecf20Sopenharmony_ci		tid = ieee80211_get_tid(hdr);
30788c2ecf20Sopenharmony_ci	mic_hdr[12] = tid;
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci	ret = crypto_shash_update(desc, mic_hdr, 16);
30818c2ecf20Sopenharmony_ci	if (ret)
30828c2ecf20Sopenharmony_ci		goto out;
30838c2ecf20Sopenharmony_ci	ret = crypto_shash_update(desc, data, data_len);
30848c2ecf20Sopenharmony_ci	if (ret)
30858c2ecf20Sopenharmony_ci		goto out;
30868c2ecf20Sopenharmony_ci	ret = crypto_shash_final(desc, mic);
30878c2ecf20Sopenharmony_ciout:
30888c2ecf20Sopenharmony_ci	shash_desc_zero(desc);
30898c2ecf20Sopenharmony_ci	return ret;
30908c2ecf20Sopenharmony_ci}
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer *peer,
30938c2ecf20Sopenharmony_ci					  struct sk_buff *msdu)
30948c2ecf20Sopenharmony_ci{
30958c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)msdu->data;
30968c2ecf20Sopenharmony_ci	struct ieee80211_rx_status *rxs = IEEE80211_SKB_RXCB(msdu);
30978c2ecf20Sopenharmony_ci	struct ieee80211_key_conf *key_conf;
30988c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
30998c2ecf20Sopenharmony_ci	u8 mic[IEEE80211_CCMP_MIC_LEN];
31008c2ecf20Sopenharmony_ci	int head_len, tail_len, ret;
31018c2ecf20Sopenharmony_ci	size_t data_len;
31028c2ecf20Sopenharmony_ci	u32 hdr_len;
31038c2ecf20Sopenharmony_ci	u8 *key, *data;
31048c2ecf20Sopenharmony_ci	u8 key_idx;
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	if (ath11k_dp_rx_h_mpdu_start_enctype(rx_desc) != HAL_ENCRYPT_TYPE_TKIP_MIC)
31078c2ecf20Sopenharmony_ci		return 0;
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)(msdu->data + HAL_RX_DESC_SIZE);
31108c2ecf20Sopenharmony_ci	hdr_len = ieee80211_hdrlen(hdr->frame_control);
31118c2ecf20Sopenharmony_ci	head_len = hdr_len + HAL_RX_DESC_SIZE + IEEE80211_TKIP_IV_LEN;
31128c2ecf20Sopenharmony_ci	tail_len = IEEE80211_CCMP_MIC_LEN + IEEE80211_TKIP_ICV_LEN + FCS_LEN;
31138c2ecf20Sopenharmony_ci
31148c2ecf20Sopenharmony_ci	if (!is_multicast_ether_addr(hdr->addr1))
31158c2ecf20Sopenharmony_ci		key_idx = peer->ucast_keyidx;
31168c2ecf20Sopenharmony_ci	else
31178c2ecf20Sopenharmony_ci		key_idx = peer->mcast_keyidx;
31188c2ecf20Sopenharmony_ci
31198c2ecf20Sopenharmony_ci	key_conf = peer->keys[key_idx];
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_ci	data = msdu->data + head_len;
31228c2ecf20Sopenharmony_ci	data_len = msdu->len - head_len - tail_len;
31238c2ecf20Sopenharmony_ci	key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci	ret = ath11k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data, data_len, mic);
31268c2ecf20Sopenharmony_ci	if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN))
31278c2ecf20Sopenharmony_ci		goto mic_fail;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	return 0;
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_cimic_fail:
31328c2ecf20Sopenharmony_ci	(ATH11K_SKB_RXCB(msdu))->is_first_msdu = true;
31338c2ecf20Sopenharmony_ci	(ATH11K_SKB_RXCB(msdu))->is_last_msdu = true;
31348c2ecf20Sopenharmony_ci
31358c2ecf20Sopenharmony_ci	rxs->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_MMIC_STRIPPED |
31368c2ecf20Sopenharmony_ci		    RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
31378c2ecf20Sopenharmony_ci	skb_pull(msdu, HAL_RX_DESC_SIZE);
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
31408c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
31418c2ecf20Sopenharmony_ci			       HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
31428c2ecf20Sopenharmony_ci	ieee80211_rx(ar->hw, msdu);
31438c2ecf20Sopenharmony_ci	return -EINVAL;
31448c2ecf20Sopenharmony_ci}
31458c2ecf20Sopenharmony_ci
31468c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_undecap_frag(struct ath11k *ar, struct sk_buff *msdu,
31478c2ecf20Sopenharmony_ci					enum hal_encrypt_type enctype, u32 flags)
31488c2ecf20Sopenharmony_ci{
31498c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
31508c2ecf20Sopenharmony_ci	size_t hdr_len;
31518c2ecf20Sopenharmony_ci	size_t crypto_len;
31528c2ecf20Sopenharmony_ci
31538c2ecf20Sopenharmony_ci	if (!flags)
31548c2ecf20Sopenharmony_ci		return;
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)(msdu->data + HAL_RX_DESC_SIZE);
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci	if (flags & RX_FLAG_MIC_STRIPPED)
31598c2ecf20Sopenharmony_ci		skb_trim(msdu, msdu->len -
31608c2ecf20Sopenharmony_ci			 ath11k_dp_rx_crypto_mic_len(ar, enctype));
31618c2ecf20Sopenharmony_ci
31628c2ecf20Sopenharmony_ci	if (flags & RX_FLAG_ICV_STRIPPED)
31638c2ecf20Sopenharmony_ci		skb_trim(msdu, msdu->len -
31648c2ecf20Sopenharmony_ci			 ath11k_dp_rx_crypto_icv_len(ar, enctype));
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_ci	if (flags & RX_FLAG_IV_STRIPPED) {
31678c2ecf20Sopenharmony_ci		hdr_len = ieee80211_hdrlen(hdr->frame_control);
31688c2ecf20Sopenharmony_ci		crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype);
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_ci		memmove((void *)msdu->data + HAL_RX_DESC_SIZE + crypto_len,
31718c2ecf20Sopenharmony_ci			(void *)msdu->data + HAL_RX_DESC_SIZE, hdr_len);
31728c2ecf20Sopenharmony_ci		skb_pull(msdu, crypto_len);
31738c2ecf20Sopenharmony_ci	}
31748c2ecf20Sopenharmony_ci}
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_defrag(struct ath11k *ar,
31778c2ecf20Sopenharmony_ci				 struct ath11k_peer *peer,
31788c2ecf20Sopenharmony_ci				 struct dp_rx_tid *rx_tid,
31798c2ecf20Sopenharmony_ci				 struct sk_buff **defrag_skb)
31808c2ecf20Sopenharmony_ci{
31818c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc;
31828c2ecf20Sopenharmony_ci	struct sk_buff *skb, *first_frag, *last_frag;
31838c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
31848c2ecf20Sopenharmony_ci	enum hal_encrypt_type enctype;
31858c2ecf20Sopenharmony_ci	bool is_decrypted = false;
31868c2ecf20Sopenharmony_ci	int msdu_len = 0;
31878c2ecf20Sopenharmony_ci	int extra_space;
31888c2ecf20Sopenharmony_ci	u32 flags;
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	first_frag = skb_peek(&rx_tid->rx_frags);
31918c2ecf20Sopenharmony_ci	last_frag = skb_peek_tail(&rx_tid->rx_frags);
31928c2ecf20Sopenharmony_ci
31938c2ecf20Sopenharmony_ci	skb_queue_walk(&rx_tid->rx_frags, skb) {
31948c2ecf20Sopenharmony_ci		flags = 0;
31958c2ecf20Sopenharmony_ci		rx_desc = (struct hal_rx_desc *)skb->data;
31968c2ecf20Sopenharmony_ci		hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci		enctype = ath11k_dp_rx_h_mpdu_start_enctype(rx_desc);
31998c2ecf20Sopenharmony_ci		if (enctype != HAL_ENCRYPT_TYPE_OPEN)
32008c2ecf20Sopenharmony_ci			is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc);
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci		if (is_decrypted) {
32038c2ecf20Sopenharmony_ci			if (skb != first_frag)
32048c2ecf20Sopenharmony_ci				flags |=  RX_FLAG_IV_STRIPPED;
32058c2ecf20Sopenharmony_ci			if (skb != last_frag)
32068c2ecf20Sopenharmony_ci				flags |= RX_FLAG_ICV_STRIPPED |
32078c2ecf20Sopenharmony_ci					 RX_FLAG_MIC_STRIPPED;
32088c2ecf20Sopenharmony_ci		}
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci		/* RX fragments are always raw packets */
32118c2ecf20Sopenharmony_ci		if (skb != last_frag)
32128c2ecf20Sopenharmony_ci			skb_trim(skb, skb->len - FCS_LEN);
32138c2ecf20Sopenharmony_ci		ath11k_dp_rx_h_undecap_frag(ar, skb, enctype, flags);
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci		if (skb != first_frag)
32168c2ecf20Sopenharmony_ci			skb_pull(skb, HAL_RX_DESC_SIZE +
32178c2ecf20Sopenharmony_ci				      ieee80211_hdrlen(hdr->frame_control));
32188c2ecf20Sopenharmony_ci		msdu_len += skb->len;
32198c2ecf20Sopenharmony_ci	}
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci	extra_space = msdu_len - (DP_RX_BUFFER_SIZE + skb_tailroom(first_frag));
32228c2ecf20Sopenharmony_ci	if (extra_space > 0 &&
32238c2ecf20Sopenharmony_ci	    (pskb_expand_head(first_frag, 0, extra_space, GFP_ATOMIC) < 0))
32248c2ecf20Sopenharmony_ci		return -ENOMEM;
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	__skb_unlink(first_frag, &rx_tid->rx_frags);
32278c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&rx_tid->rx_frags))) {
32288c2ecf20Sopenharmony_ci		skb_put_data(first_frag, skb->data, skb->len);
32298c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
32308c2ecf20Sopenharmony_ci	}
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)(first_frag->data + HAL_RX_DESC_SIZE);
32338c2ecf20Sopenharmony_ci	hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
32348c2ecf20Sopenharmony_ci	ATH11K_SKB_RXCB(first_frag)->is_frag = 1;
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_ci	if (ath11k_dp_rx_h_verify_tkip_mic(ar, peer, first_frag))
32378c2ecf20Sopenharmony_ci		first_frag = NULL;
32388c2ecf20Sopenharmony_ci
32398c2ecf20Sopenharmony_ci	*defrag_skb = first_frag;
32408c2ecf20Sopenharmony_ci	return 0;
32418c2ecf20Sopenharmony_ci}
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_defrag_reo_reinject(struct ath11k *ar, struct dp_rx_tid *rx_tid,
32448c2ecf20Sopenharmony_ci					      struct sk_buff *defrag_skb)
32458c2ecf20Sopenharmony_ci{
32468c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
32478c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
32488c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_refill_ring = &dp->rx_refill_buf_ring;
32498c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)defrag_skb->data;
32508c2ecf20Sopenharmony_ci	struct hal_reo_entrance_ring *reo_ent_ring;
32518c2ecf20Sopenharmony_ci	struct hal_reo_dest_ring *reo_dest_ring;
32528c2ecf20Sopenharmony_ci	struct dp_link_desc_bank *link_desc_banks;
32538c2ecf20Sopenharmony_ci	struct hal_rx_msdu_link *msdu_link;
32548c2ecf20Sopenharmony_ci	struct hal_rx_msdu_details *msdu0;
32558c2ecf20Sopenharmony_ci	struct hal_srng *srng;
32568c2ecf20Sopenharmony_ci	dma_addr_t paddr;
32578c2ecf20Sopenharmony_ci	u32 desc_bank, msdu_info, mpdu_info;
32588c2ecf20Sopenharmony_ci	u32 dst_idx, cookie;
32598c2ecf20Sopenharmony_ci	u32 *msdu_len_offset;
32608c2ecf20Sopenharmony_ci	int ret, buf_id;
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_ci	link_desc_banks = ab->dp.link_desc_banks;
32638c2ecf20Sopenharmony_ci	reo_dest_ring = rx_tid->dst_ring_desc;
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	ath11k_hal_rx_reo_ent_paddr_get(ab, reo_dest_ring, &paddr, &desc_bank);
32668c2ecf20Sopenharmony_ci	msdu_link = (struct hal_rx_msdu_link *)(link_desc_banks[desc_bank].vaddr +
32678c2ecf20Sopenharmony_ci			(paddr - link_desc_banks[desc_bank].paddr));
32688c2ecf20Sopenharmony_ci	msdu0 = &msdu_link->msdu_link[0];
32698c2ecf20Sopenharmony_ci	dst_idx = FIELD_GET(RX_MSDU_DESC_INFO0_REO_DEST_IND, msdu0->rx_msdu_info.info0);
32708c2ecf20Sopenharmony_ci	memset(msdu0, 0, sizeof(*msdu0));
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci	msdu_info = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1) |
32738c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1) |
32748c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_CONTINUATION, 0) |
32758c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MSDU_DESC_INFO0_MSDU_LENGTH,
32768c2ecf20Sopenharmony_ci			       defrag_skb->len - HAL_RX_DESC_SIZE) |
32778c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MSDU_DESC_INFO0_REO_DEST_IND, dst_idx) |
32788c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_SA, 1) |
32798c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MSDU_DESC_INFO0_VALID_DA, 1);
32808c2ecf20Sopenharmony_ci	msdu0->rx_msdu_info.info0 = msdu_info;
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci	/* change msdu len in hal rx desc */
32838c2ecf20Sopenharmony_ci	msdu_len_offset = (u32 *)&rx_desc->msdu_start;
32848c2ecf20Sopenharmony_ci	*msdu_len_offset &= ~(RX_MSDU_START_INFO1_MSDU_LENGTH);
32858c2ecf20Sopenharmony_ci	*msdu_len_offset |= defrag_skb->len - HAL_RX_DESC_SIZE;
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci	paddr = dma_map_single(ab->dev, defrag_skb->data,
32888c2ecf20Sopenharmony_ci			       defrag_skb->len + skb_tailroom(defrag_skb),
32898c2ecf20Sopenharmony_ci			       DMA_TO_DEVICE);
32908c2ecf20Sopenharmony_ci	if (dma_mapping_error(ab->dev, paddr))
32918c2ecf20Sopenharmony_ci		return -ENOMEM;
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_refill_ring->idr_lock);
32948c2ecf20Sopenharmony_ci	buf_id = idr_alloc(&rx_refill_ring->bufs_idr, defrag_skb, 0,
32958c2ecf20Sopenharmony_ci			   rx_refill_ring->bufs_max * 3, GFP_ATOMIC);
32968c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_refill_ring->idr_lock);
32978c2ecf20Sopenharmony_ci	if (buf_id < 0) {
32988c2ecf20Sopenharmony_ci		ret = -ENOMEM;
32998c2ecf20Sopenharmony_ci		goto err_unmap_dma;
33008c2ecf20Sopenharmony_ci	}
33018c2ecf20Sopenharmony_ci
33028c2ecf20Sopenharmony_ci	ATH11K_SKB_RXCB(defrag_skb)->paddr = paddr;
33038c2ecf20Sopenharmony_ci	cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, dp->mac_id) |
33048c2ecf20Sopenharmony_ci		 FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie, HAL_RX_BUF_RBM_SW3_BM);
33078c2ecf20Sopenharmony_ci
33088c2ecf20Sopenharmony_ci	/* Fill mpdu details into reo entrace ring */
33098c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[ab->dp.reo_reinject_ring.ring_id];
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
33128c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
33138c2ecf20Sopenharmony_ci
33148c2ecf20Sopenharmony_ci	reo_ent_ring = (struct hal_reo_entrance_ring *)
33158c2ecf20Sopenharmony_ci			ath11k_hal_srng_src_get_next_entry(ab, srng);
33168c2ecf20Sopenharmony_ci	if (!reo_ent_ring) {
33178c2ecf20Sopenharmony_ci		ath11k_hal_srng_access_end(ab, srng);
33188c2ecf20Sopenharmony_ci		spin_unlock_bh(&srng->lock);
33198c2ecf20Sopenharmony_ci		ret = -ENOSPC;
33208c2ecf20Sopenharmony_ci		goto err_free_idr;
33218c2ecf20Sopenharmony_ci	}
33228c2ecf20Sopenharmony_ci	memset(reo_ent_ring, 0, sizeof(*reo_ent_ring));
33238c2ecf20Sopenharmony_ci
33248c2ecf20Sopenharmony_ci	ath11k_hal_rx_reo_ent_paddr_get(ab, reo_dest_ring, &paddr, &desc_bank);
33258c2ecf20Sopenharmony_ci	ath11k_hal_rx_buf_addr_info_set(reo_ent_ring, paddr, desc_bank,
33268c2ecf20Sopenharmony_ci					HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST);
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci	mpdu_info = FIELD_PREP(RX_MPDU_DESC_INFO0_MSDU_COUNT, 1) |
33298c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MPDU_DESC_INFO0_SEQ_NUM, rx_tid->cur_sn) |
33308c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MPDU_DESC_INFO0_FRAG_FLAG, 0) |
33318c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_SA, 1) |
33328c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_DA, 1) |
33338c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MPDU_DESC_INFO0_RAW_MPDU, 1) |
33348c2ecf20Sopenharmony_ci		    FIELD_PREP(RX_MPDU_DESC_INFO0_VALID_PN, 1);
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_ci	reo_ent_ring->rx_mpdu_info.info0 = mpdu_info;
33378c2ecf20Sopenharmony_ci	reo_ent_ring->rx_mpdu_info.meta_data = reo_dest_ring->rx_mpdu_info.meta_data;
33388c2ecf20Sopenharmony_ci	reo_ent_ring->queue_addr_lo = reo_dest_ring->queue_addr_lo;
33398c2ecf20Sopenharmony_ci	reo_ent_ring->info0 = FIELD_PREP(HAL_REO_ENTR_RING_INFO0_QUEUE_ADDR_HI,
33408c2ecf20Sopenharmony_ci					 FIELD_GET(HAL_REO_DEST_RING_INFO0_QUEUE_ADDR_HI,
33418c2ecf20Sopenharmony_ci						   reo_dest_ring->info0)) |
33428c2ecf20Sopenharmony_ci			      FIELD_PREP(HAL_REO_ENTR_RING_INFO0_DEST_IND, dst_idx);
33438c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
33448c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci	return 0;
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_cierr_free_idr:
33498c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_refill_ring->idr_lock);
33508c2ecf20Sopenharmony_ci	idr_remove(&rx_refill_ring->bufs_idr, buf_id);
33518c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_refill_ring->idr_lock);
33528c2ecf20Sopenharmony_cierr_unmap_dma:
33538c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, paddr, defrag_skb->len + skb_tailroom(defrag_skb),
33548c2ecf20Sopenharmony_ci			 DMA_TO_DEVICE);
33558c2ecf20Sopenharmony_ci	return ret;
33568c2ecf20Sopenharmony_ci}
33578c2ecf20Sopenharmony_ci
33588c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_cmp_frags(struct sk_buff *a, struct sk_buff *b)
33598c2ecf20Sopenharmony_ci{
33608c2ecf20Sopenharmony_ci	int frag1, frag2;
33618c2ecf20Sopenharmony_ci
33628c2ecf20Sopenharmony_ci	frag1 = ath11k_dp_rx_h_mpdu_start_frag_no(a);
33638c2ecf20Sopenharmony_ci	frag2 = ath11k_dp_rx_h_mpdu_start_frag_no(b);
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	return frag1 - frag2;
33668c2ecf20Sopenharmony_ci}
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_sort_frags(struct sk_buff_head *frag_list,
33698c2ecf20Sopenharmony_ci				      struct sk_buff *cur_frag)
33708c2ecf20Sopenharmony_ci{
33718c2ecf20Sopenharmony_ci	struct sk_buff *skb;
33728c2ecf20Sopenharmony_ci	int cmp;
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci	skb_queue_walk(frag_list, skb) {
33758c2ecf20Sopenharmony_ci		cmp = ath11k_dp_rx_h_cmp_frags(skb, cur_frag);
33768c2ecf20Sopenharmony_ci		if (cmp < 0)
33778c2ecf20Sopenharmony_ci			continue;
33788c2ecf20Sopenharmony_ci		__skb_queue_before(frag_list, skb, cur_frag);
33798c2ecf20Sopenharmony_ci		return;
33808c2ecf20Sopenharmony_ci	}
33818c2ecf20Sopenharmony_ci	__skb_queue_tail(frag_list, cur_frag);
33828c2ecf20Sopenharmony_ci}
33838c2ecf20Sopenharmony_ci
33848c2ecf20Sopenharmony_cistatic u64 ath11k_dp_rx_h_get_pn(struct sk_buff *skb)
33858c2ecf20Sopenharmony_ci{
33868c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
33878c2ecf20Sopenharmony_ci	u64 pn = 0;
33888c2ecf20Sopenharmony_ci	u8 *ehdr;
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)(skb->data + HAL_RX_DESC_SIZE);
33918c2ecf20Sopenharmony_ci	ehdr = skb->data + HAL_RX_DESC_SIZE + ieee80211_hdrlen(hdr->frame_control);
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci	pn = ehdr[0];
33948c2ecf20Sopenharmony_ci	pn |= (u64)ehdr[1] << 8;
33958c2ecf20Sopenharmony_ci	pn |= (u64)ehdr[4] << 16;
33968c2ecf20Sopenharmony_ci	pn |= (u64)ehdr[5] << 24;
33978c2ecf20Sopenharmony_ci	pn |= (u64)ehdr[6] << 32;
33988c2ecf20Sopenharmony_ci	pn |= (u64)ehdr[7] << 40;
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	return pn;
34018c2ecf20Sopenharmony_ci}
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_cistatic bool
34048c2ecf20Sopenharmony_ciath11k_dp_rx_h_defrag_validate_incr_pn(struct ath11k *ar, struct dp_rx_tid *rx_tid)
34058c2ecf20Sopenharmony_ci{
34068c2ecf20Sopenharmony_ci	enum hal_encrypt_type encrypt_type;
34078c2ecf20Sopenharmony_ci	struct sk_buff *first_frag, *skb;
34088c2ecf20Sopenharmony_ci	struct hal_rx_desc *desc;
34098c2ecf20Sopenharmony_ci	u64 last_pn;
34108c2ecf20Sopenharmony_ci	u64 cur_pn;
34118c2ecf20Sopenharmony_ci
34128c2ecf20Sopenharmony_ci	first_frag = skb_peek(&rx_tid->rx_frags);
34138c2ecf20Sopenharmony_ci	desc = (struct hal_rx_desc *)first_frag->data;
34148c2ecf20Sopenharmony_ci
34158c2ecf20Sopenharmony_ci	encrypt_type = ath11k_dp_rx_h_mpdu_start_enctype(desc);
34168c2ecf20Sopenharmony_ci	if (encrypt_type != HAL_ENCRYPT_TYPE_CCMP_128 &&
34178c2ecf20Sopenharmony_ci	    encrypt_type != HAL_ENCRYPT_TYPE_CCMP_256 &&
34188c2ecf20Sopenharmony_ci	    encrypt_type != HAL_ENCRYPT_TYPE_GCMP_128 &&
34198c2ecf20Sopenharmony_ci	    encrypt_type != HAL_ENCRYPT_TYPE_AES_GCMP_256)
34208c2ecf20Sopenharmony_ci		return true;
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	last_pn = ath11k_dp_rx_h_get_pn(first_frag);
34238c2ecf20Sopenharmony_ci	skb_queue_walk(&rx_tid->rx_frags, skb) {
34248c2ecf20Sopenharmony_ci		if (skb == first_frag)
34258c2ecf20Sopenharmony_ci			continue;
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_ci		cur_pn = ath11k_dp_rx_h_get_pn(skb);
34288c2ecf20Sopenharmony_ci		if (cur_pn != last_pn + 1)
34298c2ecf20Sopenharmony_ci			return false;
34308c2ecf20Sopenharmony_ci		last_pn = cur_pn;
34318c2ecf20Sopenharmony_ci	}
34328c2ecf20Sopenharmony_ci	return true;
34338c2ecf20Sopenharmony_ci}
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar,
34368c2ecf20Sopenharmony_ci				    struct sk_buff *msdu,
34378c2ecf20Sopenharmony_ci				    u32 *ring_desc)
34388c2ecf20Sopenharmony_ci{
34398c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
34408c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc;
34418c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
34428c2ecf20Sopenharmony_ci	struct dp_rx_tid *rx_tid;
34438c2ecf20Sopenharmony_ci	struct sk_buff *defrag_skb = NULL;
34448c2ecf20Sopenharmony_ci	u32 peer_id;
34458c2ecf20Sopenharmony_ci	u16 seqno, frag_no;
34468c2ecf20Sopenharmony_ci	u8 tid;
34478c2ecf20Sopenharmony_ci	int ret = 0;
34488c2ecf20Sopenharmony_ci	bool more_frags;
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci	rx_desc = (struct hal_rx_desc *)msdu->data;
34518c2ecf20Sopenharmony_ci	peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(rx_desc);
34528c2ecf20Sopenharmony_ci	tid = ath11k_dp_rx_h_mpdu_start_tid(rx_desc);
34538c2ecf20Sopenharmony_ci	seqno = ath11k_dp_rx_h_mpdu_start_seq_no(rx_desc);
34548c2ecf20Sopenharmony_ci	frag_no = ath11k_dp_rx_h_mpdu_start_frag_no(msdu);
34558c2ecf20Sopenharmony_ci	more_frags = ath11k_dp_rx_h_mpdu_start_more_frags(msdu);
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci	if (!ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(rx_desc) ||
34588c2ecf20Sopenharmony_ci	    !ath11k_dp_rx_h_mpdu_start_fc_valid(rx_desc) ||
34598c2ecf20Sopenharmony_ci	    tid > IEEE80211_NUM_TIDS)
34608c2ecf20Sopenharmony_ci		return -EINVAL;
34618c2ecf20Sopenharmony_ci
34628c2ecf20Sopenharmony_ci	/* received unfragmented packet in reo
34638c2ecf20Sopenharmony_ci	 * exception ring, this shouldn't happen
34648c2ecf20Sopenharmony_ci	 * as these packets typically come from
34658c2ecf20Sopenharmony_ci	 * reo2sw srngs.
34668c2ecf20Sopenharmony_ci	 */
34678c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!frag_no && !more_frags))
34688c2ecf20Sopenharmony_ci		return -EINVAL;
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
34718c2ecf20Sopenharmony_ci	peer = ath11k_peer_find_by_id(ab, peer_id);
34728c2ecf20Sopenharmony_ci	if (!peer) {
34738c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to find the peer to de-fragment received fragment peer_id %d\n",
34748c2ecf20Sopenharmony_ci			    peer_id);
34758c2ecf20Sopenharmony_ci		ret = -ENOENT;
34768c2ecf20Sopenharmony_ci		goto out_unlock;
34778c2ecf20Sopenharmony_ci	}
34788c2ecf20Sopenharmony_ci	rx_tid = &peer->rx_tid[tid];
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_ci	if ((!skb_queue_empty(&rx_tid->rx_frags) && seqno != rx_tid->cur_sn) ||
34818c2ecf20Sopenharmony_ci	    skb_queue_empty(&rx_tid->rx_frags)) {
34828c2ecf20Sopenharmony_ci		/* Flush stored fragments and start a new sequence */
34838c2ecf20Sopenharmony_ci		ath11k_dp_rx_frags_cleanup(rx_tid, true);
34848c2ecf20Sopenharmony_ci		rx_tid->cur_sn = seqno;
34858c2ecf20Sopenharmony_ci	}
34868c2ecf20Sopenharmony_ci
34878c2ecf20Sopenharmony_ci	if (rx_tid->rx_frag_bitmap & BIT(frag_no)) {
34888c2ecf20Sopenharmony_ci		/* Fragment already present */
34898c2ecf20Sopenharmony_ci		ret = -EINVAL;
34908c2ecf20Sopenharmony_ci		goto out_unlock;
34918c2ecf20Sopenharmony_ci	}
34928c2ecf20Sopenharmony_ci
34938c2ecf20Sopenharmony_ci	if (frag_no > __fls(rx_tid->rx_frag_bitmap))
34948c2ecf20Sopenharmony_ci		__skb_queue_tail(&rx_tid->rx_frags, msdu);
34958c2ecf20Sopenharmony_ci	else
34968c2ecf20Sopenharmony_ci		ath11k_dp_rx_h_sort_frags(&rx_tid->rx_frags, msdu);
34978c2ecf20Sopenharmony_ci
34988c2ecf20Sopenharmony_ci	rx_tid->rx_frag_bitmap |= BIT(frag_no);
34998c2ecf20Sopenharmony_ci	if (!more_frags)
35008c2ecf20Sopenharmony_ci		rx_tid->last_frag_no = frag_no;
35018c2ecf20Sopenharmony_ci
35028c2ecf20Sopenharmony_ci	if (frag_no == 0) {
35038c2ecf20Sopenharmony_ci		rx_tid->dst_ring_desc = kmemdup(ring_desc,
35048c2ecf20Sopenharmony_ci						sizeof(*rx_tid->dst_ring_desc),
35058c2ecf20Sopenharmony_ci						GFP_ATOMIC);
35068c2ecf20Sopenharmony_ci		if (!rx_tid->dst_ring_desc) {
35078c2ecf20Sopenharmony_ci			ret = -ENOMEM;
35088c2ecf20Sopenharmony_ci			goto out_unlock;
35098c2ecf20Sopenharmony_ci		}
35108c2ecf20Sopenharmony_ci	} else {
35118c2ecf20Sopenharmony_ci		ath11k_dp_rx_link_desc_return(ab, ring_desc,
35128c2ecf20Sopenharmony_ci					      HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
35138c2ecf20Sopenharmony_ci	}
35148c2ecf20Sopenharmony_ci
35158c2ecf20Sopenharmony_ci	if (!rx_tid->last_frag_no ||
35168c2ecf20Sopenharmony_ci	    rx_tid->rx_frag_bitmap != GENMASK(rx_tid->last_frag_no, 0)) {
35178c2ecf20Sopenharmony_ci		mod_timer(&rx_tid->frag_timer, jiffies +
35188c2ecf20Sopenharmony_ci					       ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS);
35198c2ecf20Sopenharmony_ci		goto out_unlock;
35208c2ecf20Sopenharmony_ci	}
35218c2ecf20Sopenharmony_ci
35228c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
35238c2ecf20Sopenharmony_ci	del_timer_sync(&rx_tid->frag_timer);
35248c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
35258c2ecf20Sopenharmony_ci
35268c2ecf20Sopenharmony_ci	peer = ath11k_peer_find_by_id(ab, peer_id);
35278c2ecf20Sopenharmony_ci	if (!peer)
35288c2ecf20Sopenharmony_ci		goto err_frags_cleanup;
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci	if (!ath11k_dp_rx_h_defrag_validate_incr_pn(ar, rx_tid))
35318c2ecf20Sopenharmony_ci		goto err_frags_cleanup;
35328c2ecf20Sopenharmony_ci
35338c2ecf20Sopenharmony_ci	if (ath11k_dp_rx_h_defrag(ar, peer, rx_tid, &defrag_skb))
35348c2ecf20Sopenharmony_ci		goto err_frags_cleanup;
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	if (!defrag_skb)
35378c2ecf20Sopenharmony_ci		goto err_frags_cleanup;
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ci	if (ath11k_dp_rx_h_defrag_reo_reinject(ar, rx_tid, defrag_skb))
35408c2ecf20Sopenharmony_ci		goto err_frags_cleanup;
35418c2ecf20Sopenharmony_ci
35428c2ecf20Sopenharmony_ci	ath11k_dp_rx_frags_cleanup(rx_tid, false);
35438c2ecf20Sopenharmony_ci	goto out_unlock;
35448c2ecf20Sopenharmony_ci
35458c2ecf20Sopenharmony_cierr_frags_cleanup:
35468c2ecf20Sopenharmony_ci	dev_kfree_skb_any(defrag_skb);
35478c2ecf20Sopenharmony_ci	ath11k_dp_rx_frags_cleanup(rx_tid, true);
35488c2ecf20Sopenharmony_ciout_unlock:
35498c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
35508c2ecf20Sopenharmony_ci	return ret;
35518c2ecf20Sopenharmony_ci}
35528c2ecf20Sopenharmony_ci
35538c2ecf20Sopenharmony_cistatic int
35548c2ecf20Sopenharmony_ciath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool drop)
35558c2ecf20Sopenharmony_ci{
35568c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
35578c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
35588c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
35598c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
35608c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc;
35618c2ecf20Sopenharmony_ci	u8 *hdr_status;
35628c2ecf20Sopenharmony_ci	u16 msdu_len;
35638c2ecf20Sopenharmony_ci
35648c2ecf20Sopenharmony_ci	spin_lock_bh(&rx_ring->idr_lock);
35658c2ecf20Sopenharmony_ci	msdu = idr_find(&rx_ring->bufs_idr, buf_id);
35668c2ecf20Sopenharmony_ci	if (!msdu) {
35678c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "rx err buf with invalid buf_id %d\n",
35688c2ecf20Sopenharmony_ci			    buf_id);
35698c2ecf20Sopenharmony_ci		spin_unlock_bh(&rx_ring->idr_lock);
35708c2ecf20Sopenharmony_ci		return -EINVAL;
35718c2ecf20Sopenharmony_ci	}
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_ci	idr_remove(&rx_ring->bufs_idr, buf_id);
35748c2ecf20Sopenharmony_ci	spin_unlock_bh(&rx_ring->idr_lock);
35758c2ecf20Sopenharmony_ci
35768c2ecf20Sopenharmony_ci	rxcb = ATH11K_SKB_RXCB(msdu);
35778c2ecf20Sopenharmony_ci	dma_unmap_single(ar->ab->dev, rxcb->paddr,
35788c2ecf20Sopenharmony_ci			 msdu->len + skb_tailroom(msdu),
35798c2ecf20Sopenharmony_ci			 DMA_FROM_DEVICE);
35808c2ecf20Sopenharmony_ci
35818c2ecf20Sopenharmony_ci	if (drop) {
35828c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
35838c2ecf20Sopenharmony_ci		return 0;
35848c2ecf20Sopenharmony_ci	}
35858c2ecf20Sopenharmony_ci
35868c2ecf20Sopenharmony_ci	rcu_read_lock();
35878c2ecf20Sopenharmony_ci	if (!rcu_dereference(ar->ab->pdevs_active[ar->pdev_idx])) {
35888c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
35898c2ecf20Sopenharmony_ci		goto exit;
35908c2ecf20Sopenharmony_ci	}
35918c2ecf20Sopenharmony_ci
35928c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
35938c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
35948c2ecf20Sopenharmony_ci		goto exit;
35958c2ecf20Sopenharmony_ci	}
35968c2ecf20Sopenharmony_ci
35978c2ecf20Sopenharmony_ci	rx_desc = (struct hal_rx_desc *)msdu->data;
35988c2ecf20Sopenharmony_ci	msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc);
35998c2ecf20Sopenharmony_ci	if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) {
36008c2ecf20Sopenharmony_ci		hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc);
36018c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "invalid msdu leng %u", msdu_len);
36028c2ecf20Sopenharmony_ci		ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", hdr_status,
36038c2ecf20Sopenharmony_ci				sizeof(struct ieee80211_hdr));
36048c2ecf20Sopenharmony_ci		ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", rx_desc,
36058c2ecf20Sopenharmony_ci				sizeof(struct hal_rx_desc));
36068c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
36078c2ecf20Sopenharmony_ci		goto exit;
36088c2ecf20Sopenharmony_ci	}
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci	skb_put(msdu, HAL_RX_DESC_SIZE + msdu_len);
36118c2ecf20Sopenharmony_ci
36128c2ecf20Sopenharmony_ci	if (ath11k_dp_rx_frag_h_mpdu(ar, msdu, ring_desc)) {
36138c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
36148c2ecf20Sopenharmony_ci		ath11k_dp_rx_link_desc_return(ar->ab, ring_desc,
36158c2ecf20Sopenharmony_ci					      HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
36168c2ecf20Sopenharmony_ci	}
36178c2ecf20Sopenharmony_ciexit:
36188c2ecf20Sopenharmony_ci	rcu_read_unlock();
36198c2ecf20Sopenharmony_ci	return 0;
36208c2ecf20Sopenharmony_ci}
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ciint ath11k_dp_process_rx_err(struct ath11k_base *ab, struct napi_struct *napi,
36238c2ecf20Sopenharmony_ci			     int budget)
36248c2ecf20Sopenharmony_ci{
36258c2ecf20Sopenharmony_ci	u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC];
36268c2ecf20Sopenharmony_ci	struct dp_link_desc_bank *link_desc_banks;
36278c2ecf20Sopenharmony_ci	enum hal_rx_buf_return_buf_manager rbm;
36288c2ecf20Sopenharmony_ci	int tot_n_bufs_reaped, quota, ret, i;
36298c2ecf20Sopenharmony_ci	int n_bufs_reaped[MAX_RADIOS] = {0};
36308c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring;
36318c2ecf20Sopenharmony_ci	struct dp_srng *reo_except;
36328c2ecf20Sopenharmony_ci	u32 desc_bank, num_msdus;
36338c2ecf20Sopenharmony_ci	struct hal_srng *srng;
36348c2ecf20Sopenharmony_ci	struct ath11k_dp *dp;
36358c2ecf20Sopenharmony_ci	void *link_desc_va;
36368c2ecf20Sopenharmony_ci	int buf_id, mac_id;
36378c2ecf20Sopenharmony_ci	struct ath11k *ar;
36388c2ecf20Sopenharmony_ci	dma_addr_t paddr;
36398c2ecf20Sopenharmony_ci	u32 *desc;
36408c2ecf20Sopenharmony_ci	bool is_frag;
36418c2ecf20Sopenharmony_ci	u8 drop = 0;
36428c2ecf20Sopenharmony_ci
36438c2ecf20Sopenharmony_ci	tot_n_bufs_reaped = 0;
36448c2ecf20Sopenharmony_ci	quota = budget;
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	dp = &ab->dp;
36478c2ecf20Sopenharmony_ci	reo_except = &dp->reo_except_ring;
36488c2ecf20Sopenharmony_ci	link_desc_banks = dp->link_desc_banks;
36498c2ecf20Sopenharmony_ci
36508c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[reo_except->ring_id];
36518c2ecf20Sopenharmony_ci
36528c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
36538c2ecf20Sopenharmony_ci
36548c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
36558c2ecf20Sopenharmony_ci
36568c2ecf20Sopenharmony_ci	while (budget &&
36578c2ecf20Sopenharmony_ci	       (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
36588c2ecf20Sopenharmony_ci		struct hal_reo_dest_ring *reo_desc = (struct hal_reo_dest_ring *)desc;
36598c2ecf20Sopenharmony_ci
36608c2ecf20Sopenharmony_ci		ab->soc_stats.err_ring_pkts++;
36618c2ecf20Sopenharmony_ci		ret = ath11k_hal_desc_reo_parse_err(ab, desc, &paddr,
36628c2ecf20Sopenharmony_ci						    &desc_bank);
36638c2ecf20Sopenharmony_ci		if (ret) {
36648c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to parse error reo desc %d\n",
36658c2ecf20Sopenharmony_ci				    ret);
36668c2ecf20Sopenharmony_ci			continue;
36678c2ecf20Sopenharmony_ci		}
36688c2ecf20Sopenharmony_ci		link_desc_va = link_desc_banks[desc_bank].vaddr +
36698c2ecf20Sopenharmony_ci			       (paddr - link_desc_banks[desc_bank].paddr);
36708c2ecf20Sopenharmony_ci		ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies,
36718c2ecf20Sopenharmony_ci						 &rbm);
36728c2ecf20Sopenharmony_ci		if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST &&
36738c2ecf20Sopenharmony_ci		    rbm != HAL_RX_BUF_RBM_SW3_BM) {
36748c2ecf20Sopenharmony_ci			ab->soc_stats.invalid_rbm++;
36758c2ecf20Sopenharmony_ci			ath11k_warn(ab, "invalid return buffer manager %d\n", rbm);
36768c2ecf20Sopenharmony_ci			ath11k_dp_rx_link_desc_return(ab, desc,
36778c2ecf20Sopenharmony_ci						      HAL_WBM_REL_BM_ACT_REL_MSDU);
36788c2ecf20Sopenharmony_ci			continue;
36798c2ecf20Sopenharmony_ci		}
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_ci		is_frag = !!(reo_desc->rx_mpdu_info.info0 & RX_MPDU_DESC_INFO0_FRAG_FLAG);
36828c2ecf20Sopenharmony_ci
36838c2ecf20Sopenharmony_ci		/* Process only rx fragments with one msdu per link desc below, and drop
36848c2ecf20Sopenharmony_ci		 * msdu's indicated due to error reasons.
36858c2ecf20Sopenharmony_ci		 */
36868c2ecf20Sopenharmony_ci		if (!is_frag || num_msdus > 1) {
36878c2ecf20Sopenharmony_ci			drop = 1;
36888c2ecf20Sopenharmony_ci			/* Return the link desc back to wbm idle list */
36898c2ecf20Sopenharmony_ci			ath11k_dp_rx_link_desc_return(ab, desc,
36908c2ecf20Sopenharmony_ci						      HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
36918c2ecf20Sopenharmony_ci		}
36928c2ecf20Sopenharmony_ci
36938c2ecf20Sopenharmony_ci		for (i = 0; i < num_msdus; i++) {
36948c2ecf20Sopenharmony_ci			buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
36958c2ecf20Sopenharmony_ci					   msdu_cookies[i]);
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci			mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID,
36988c2ecf20Sopenharmony_ci					   msdu_cookies[i]);
36998c2ecf20Sopenharmony_ci
37008c2ecf20Sopenharmony_ci			ar = ab->pdevs[mac_id].ar;
37018c2ecf20Sopenharmony_ci
37028c2ecf20Sopenharmony_ci			if (!ath11k_dp_process_rx_err_buf(ar, desc, buf_id, drop)) {
37038c2ecf20Sopenharmony_ci				n_bufs_reaped[mac_id]++;
37048c2ecf20Sopenharmony_ci				tot_n_bufs_reaped++;
37058c2ecf20Sopenharmony_ci			}
37068c2ecf20Sopenharmony_ci		}
37078c2ecf20Sopenharmony_ci
37088c2ecf20Sopenharmony_ci		if (tot_n_bufs_reaped >= quota) {
37098c2ecf20Sopenharmony_ci			tot_n_bufs_reaped = quota;
37108c2ecf20Sopenharmony_ci			goto exit;
37118c2ecf20Sopenharmony_ci		}
37128c2ecf20Sopenharmony_ci
37138c2ecf20Sopenharmony_ci		budget = quota - tot_n_bufs_reaped;
37148c2ecf20Sopenharmony_ci	}
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ciexit:
37178c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
37188c2ecf20Sopenharmony_ci
37198c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
37208c2ecf20Sopenharmony_ci
37218c2ecf20Sopenharmony_ci	for (i = 0; i <  ab->num_radios; i++) {
37228c2ecf20Sopenharmony_ci		if (!n_bufs_reaped[i])
37238c2ecf20Sopenharmony_ci			continue;
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci		ar = ab->pdevs[i].ar;
37268c2ecf20Sopenharmony_ci		rx_ring = &ar->dp.rx_refill_buf_ring;
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_ci		ath11k_dp_rxbufs_replenish(ab, i, rx_ring, n_bufs_reaped[i],
37298c2ecf20Sopenharmony_ci					   HAL_RX_BUF_RBM_SW3_BM);
37308c2ecf20Sopenharmony_ci	}
37318c2ecf20Sopenharmony_ci
37328c2ecf20Sopenharmony_ci	return tot_n_bufs_reaped;
37338c2ecf20Sopenharmony_ci}
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_null_q_desc_sg_drop(struct ath11k *ar,
37368c2ecf20Sopenharmony_ci					     int msdu_len,
37378c2ecf20Sopenharmony_ci					     struct sk_buff_head *msdu_list)
37388c2ecf20Sopenharmony_ci{
37398c2ecf20Sopenharmony_ci	struct sk_buff *skb, *tmp;
37408c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
37418c2ecf20Sopenharmony_ci	int n_buffs;
37428c2ecf20Sopenharmony_ci
37438c2ecf20Sopenharmony_ci	n_buffs = DIV_ROUND_UP(msdu_len,
37448c2ecf20Sopenharmony_ci			       (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE));
37458c2ecf20Sopenharmony_ci
37468c2ecf20Sopenharmony_ci	skb_queue_walk_safe(msdu_list, skb, tmp) {
37478c2ecf20Sopenharmony_ci		rxcb = ATH11K_SKB_RXCB(skb);
37488c2ecf20Sopenharmony_ci		if (rxcb->err_rel_src == HAL_WBM_REL_SRC_MODULE_REO &&
37498c2ecf20Sopenharmony_ci		    rxcb->err_code == HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO) {
37508c2ecf20Sopenharmony_ci			if (!n_buffs)
37518c2ecf20Sopenharmony_ci				break;
37528c2ecf20Sopenharmony_ci			__skb_unlink(skb, msdu_list);
37538c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
37548c2ecf20Sopenharmony_ci			n_buffs--;
37558c2ecf20Sopenharmony_ci		}
37568c2ecf20Sopenharmony_ci	}
37578c2ecf20Sopenharmony_ci}
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu,
37608c2ecf20Sopenharmony_ci				      struct ieee80211_rx_status *status,
37618c2ecf20Sopenharmony_ci				      struct sk_buff_head *msdu_list)
37628c2ecf20Sopenharmony_ci{
37638c2ecf20Sopenharmony_ci	u16 msdu_len;
37648c2ecf20Sopenharmony_ci	struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
37658c2ecf20Sopenharmony_ci	u8 l3pad_bytes;
37668c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci	msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc);
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_ci	if (!rxcb->is_frag && ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE)) {
37718c2ecf20Sopenharmony_ci		/* First buffer will be freed by the caller, so deduct it's length */
37728c2ecf20Sopenharmony_ci		msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE);
37738c2ecf20Sopenharmony_ci		ath11k_dp_rx_null_q_desc_sg_drop(ar, msdu_len, msdu_list);
37748c2ecf20Sopenharmony_ci		return -EINVAL;
37758c2ecf20Sopenharmony_ci	}
37768c2ecf20Sopenharmony_ci
37778c2ecf20Sopenharmony_ci	if (!ath11k_dp_rx_h_attn_msdu_done(desc)) {
37788c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
37798c2ecf20Sopenharmony_ci			    "msdu_done bit not set in null_q_des processing\n");
37808c2ecf20Sopenharmony_ci		__skb_queue_purge(msdu_list);
37818c2ecf20Sopenharmony_ci		return -EIO;
37828c2ecf20Sopenharmony_ci	}
37838c2ecf20Sopenharmony_ci
37848c2ecf20Sopenharmony_ci	/* Handle NULL queue descriptor violations arising out a missing
37858c2ecf20Sopenharmony_ci	 * REO queue for a given peer or a given TID. This typically
37868c2ecf20Sopenharmony_ci	 * may happen if a packet is received on a QOS enabled TID before the
37878c2ecf20Sopenharmony_ci	 * ADDBA negotiation for that TID, when the TID queue is setup. Or
37888c2ecf20Sopenharmony_ci	 * it may also happen for MC/BC frames if they are not routed to the
37898c2ecf20Sopenharmony_ci	 * non-QOS TID queue, in the absence of any other default TID queue.
37908c2ecf20Sopenharmony_ci	 * This error can show up both in a REO destination or WBM release ring.
37918c2ecf20Sopenharmony_ci	 */
37928c2ecf20Sopenharmony_ci
37938c2ecf20Sopenharmony_ci	rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc);
37948c2ecf20Sopenharmony_ci	rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc);
37958c2ecf20Sopenharmony_ci
37968c2ecf20Sopenharmony_ci	if (rxcb->is_frag) {
37978c2ecf20Sopenharmony_ci		skb_pull(msdu, HAL_RX_DESC_SIZE);
37988c2ecf20Sopenharmony_ci	} else {
37998c2ecf20Sopenharmony_ci		l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc);
38008c2ecf20Sopenharmony_ci
38018c2ecf20Sopenharmony_ci		if ((HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE)
38028c2ecf20Sopenharmony_ci			return -EINVAL;
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci		skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
38058c2ecf20Sopenharmony_ci		skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes);
38068c2ecf20Sopenharmony_ci	}
38078c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_ppdu(ar, desc, status);
38088c2ecf20Sopenharmony_ci
38098c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_mpdu(ar, msdu, desc, status);
38108c2ecf20Sopenharmony_ci
38118c2ecf20Sopenharmony_ci	rxcb->tid = ath11k_dp_rx_h_mpdu_start_tid(desc);
38128c2ecf20Sopenharmony_ci
38138c2ecf20Sopenharmony_ci	/* Please note that caller will having the access to msdu and completing
38148c2ecf20Sopenharmony_ci	 * rx with mac80211. Need not worry about cleaning up amsdu_list.
38158c2ecf20Sopenharmony_ci	 */
38168c2ecf20Sopenharmony_ci
38178c2ecf20Sopenharmony_ci	return 0;
38188c2ecf20Sopenharmony_ci}
38198c2ecf20Sopenharmony_ci
38208c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu,
38218c2ecf20Sopenharmony_ci				   struct ieee80211_rx_status *status,
38228c2ecf20Sopenharmony_ci				   struct sk_buff_head *msdu_list)
38238c2ecf20Sopenharmony_ci{
38248c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
38258c2ecf20Sopenharmony_ci	bool drop = false;
38268c2ecf20Sopenharmony_ci
38278c2ecf20Sopenharmony_ci	ar->ab->soc_stats.reo_error[rxcb->err_code]++;
38288c2ecf20Sopenharmony_ci
38298c2ecf20Sopenharmony_ci	switch (rxcb->err_code) {
38308c2ecf20Sopenharmony_ci	case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO:
38318c2ecf20Sopenharmony_ci		if (ath11k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list))
38328c2ecf20Sopenharmony_ci			drop = true;
38338c2ecf20Sopenharmony_ci		break;
38348c2ecf20Sopenharmony_ci	case HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED:
38358c2ecf20Sopenharmony_ci		/* TODO: Do not drop PN failed packets in the driver;
38368c2ecf20Sopenharmony_ci		 * instead, it is good to drop such packets in mac80211
38378c2ecf20Sopenharmony_ci		 * after incrementing the replay counters.
38388c2ecf20Sopenharmony_ci		 */
38398c2ecf20Sopenharmony_ci		fallthrough;
38408c2ecf20Sopenharmony_ci	default:
38418c2ecf20Sopenharmony_ci		/* TODO: Review other errors and process them to mac80211
38428c2ecf20Sopenharmony_ci		 * as appropriate.
38438c2ecf20Sopenharmony_ci		 */
38448c2ecf20Sopenharmony_ci		drop = true;
38458c2ecf20Sopenharmony_ci		break;
38468c2ecf20Sopenharmony_ci	}
38478c2ecf20Sopenharmony_ci
38488c2ecf20Sopenharmony_ci	return drop;
38498c2ecf20Sopenharmony_ci}
38508c2ecf20Sopenharmony_ci
38518c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
38528c2ecf20Sopenharmony_ci					struct ieee80211_rx_status *status)
38538c2ecf20Sopenharmony_ci{
38548c2ecf20Sopenharmony_ci	u16 msdu_len;
38558c2ecf20Sopenharmony_ci	struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
38568c2ecf20Sopenharmony_ci	u8 l3pad_bytes;
38578c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
38588c2ecf20Sopenharmony_ci
38598c2ecf20Sopenharmony_ci	rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc);
38608c2ecf20Sopenharmony_ci	rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc);
38618c2ecf20Sopenharmony_ci
38628c2ecf20Sopenharmony_ci	l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc);
38638c2ecf20Sopenharmony_ci	msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc);
38648c2ecf20Sopenharmony_ci	skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
38658c2ecf20Sopenharmony_ci	skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes);
38668c2ecf20Sopenharmony_ci
38678c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_ppdu(ar, desc, status);
38688c2ecf20Sopenharmony_ci
38698c2ecf20Sopenharmony_ci	status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
38708c2ecf20Sopenharmony_ci			 RX_FLAG_DECRYPTED);
38718c2ecf20Sopenharmony_ci
38728c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_undecap(ar, msdu, desc,
38738c2ecf20Sopenharmony_ci			       HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
38748c2ecf20Sopenharmony_ci}
38758c2ecf20Sopenharmony_ci
38768c2ecf20Sopenharmony_cistatic bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar,  struct sk_buff *msdu,
38778c2ecf20Sopenharmony_ci				     struct ieee80211_rx_status *status)
38788c2ecf20Sopenharmony_ci{
38798c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
38808c2ecf20Sopenharmony_ci	bool drop = false;
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_ci	ar->ab->soc_stats.rxdma_error[rxcb->err_code]++;
38838c2ecf20Sopenharmony_ci
38848c2ecf20Sopenharmony_ci	switch (rxcb->err_code) {
38858c2ecf20Sopenharmony_ci	case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
38868c2ecf20Sopenharmony_ci		ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
38878c2ecf20Sopenharmony_ci		break;
38888c2ecf20Sopenharmony_ci	default:
38898c2ecf20Sopenharmony_ci		/* TODO: Review other rxdma error code to check if anything is
38908c2ecf20Sopenharmony_ci		 * worth reporting to mac80211
38918c2ecf20Sopenharmony_ci		 */
38928c2ecf20Sopenharmony_ci		drop = true;
38938c2ecf20Sopenharmony_ci		break;
38948c2ecf20Sopenharmony_ci	}
38958c2ecf20Sopenharmony_ci
38968c2ecf20Sopenharmony_ci	return drop;
38978c2ecf20Sopenharmony_ci}
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_wbm_err(struct ath11k *ar,
39008c2ecf20Sopenharmony_ci				 struct napi_struct *napi,
39018c2ecf20Sopenharmony_ci				 struct sk_buff *msdu,
39028c2ecf20Sopenharmony_ci				 struct sk_buff_head *msdu_list)
39038c2ecf20Sopenharmony_ci{
39048c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
39058c2ecf20Sopenharmony_ci	struct ieee80211_rx_status rxs = {0};
39068c2ecf20Sopenharmony_ci	struct ieee80211_rx_status *status;
39078c2ecf20Sopenharmony_ci	bool drop = true;
39088c2ecf20Sopenharmony_ci
39098c2ecf20Sopenharmony_ci	switch (rxcb->err_rel_src) {
39108c2ecf20Sopenharmony_ci	case HAL_WBM_REL_SRC_MODULE_REO:
39118c2ecf20Sopenharmony_ci		drop = ath11k_dp_rx_h_reo_err(ar, msdu, &rxs, msdu_list);
39128c2ecf20Sopenharmony_ci		break;
39138c2ecf20Sopenharmony_ci	case HAL_WBM_REL_SRC_MODULE_RXDMA:
39148c2ecf20Sopenharmony_ci		drop = ath11k_dp_rx_h_rxdma_err(ar, msdu, &rxs);
39158c2ecf20Sopenharmony_ci		break;
39168c2ecf20Sopenharmony_ci	default:
39178c2ecf20Sopenharmony_ci		/* msdu will get freed */
39188c2ecf20Sopenharmony_ci		break;
39198c2ecf20Sopenharmony_ci	}
39208c2ecf20Sopenharmony_ci
39218c2ecf20Sopenharmony_ci	if (drop) {
39228c2ecf20Sopenharmony_ci		dev_kfree_skb_any(msdu);
39238c2ecf20Sopenharmony_ci		return;
39248c2ecf20Sopenharmony_ci	}
39258c2ecf20Sopenharmony_ci
39268c2ecf20Sopenharmony_ci	status = IEEE80211_SKB_RXCB(msdu);
39278c2ecf20Sopenharmony_ci	*status = rxs;
39288c2ecf20Sopenharmony_ci
39298c2ecf20Sopenharmony_ci	ath11k_dp_rx_deliver_msdu(ar, napi, msdu);
39308c2ecf20Sopenharmony_ci}
39318c2ecf20Sopenharmony_ci
39328c2ecf20Sopenharmony_ciint ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab,
39338c2ecf20Sopenharmony_ci				 struct napi_struct *napi, int budget)
39348c2ecf20Sopenharmony_ci{
39358c2ecf20Sopenharmony_ci	struct ath11k *ar;
39368c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
39378c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring;
39388c2ecf20Sopenharmony_ci	struct hal_rx_wbm_rel_info err_info;
39398c2ecf20Sopenharmony_ci	struct hal_srng *srng;
39408c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
39418c2ecf20Sopenharmony_ci	struct sk_buff_head msdu_list[MAX_RADIOS];
39428c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
39438c2ecf20Sopenharmony_ci	u32 *rx_desc;
39448c2ecf20Sopenharmony_ci	int buf_id, mac_id;
39458c2ecf20Sopenharmony_ci	int num_buffs_reaped[MAX_RADIOS] = {0};
39468c2ecf20Sopenharmony_ci	int total_num_buffs_reaped = 0;
39478c2ecf20Sopenharmony_ci	int ret, i;
39488c2ecf20Sopenharmony_ci
39498c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++)
39508c2ecf20Sopenharmony_ci		__skb_queue_head_init(&msdu_list[i]);
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id];
39538c2ecf20Sopenharmony_ci
39548c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
39578c2ecf20Sopenharmony_ci
39588c2ecf20Sopenharmony_ci	while (budget) {
39598c2ecf20Sopenharmony_ci		rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng);
39608c2ecf20Sopenharmony_ci		if (!rx_desc)
39618c2ecf20Sopenharmony_ci			break;
39628c2ecf20Sopenharmony_ci
39638c2ecf20Sopenharmony_ci		ret = ath11k_hal_wbm_desc_parse_err(ab, rx_desc, &err_info);
39648c2ecf20Sopenharmony_ci		if (ret) {
39658c2ecf20Sopenharmony_ci			ath11k_warn(ab,
39668c2ecf20Sopenharmony_ci				    "failed to parse rx error in wbm_rel ring desc %d\n",
39678c2ecf20Sopenharmony_ci				    ret);
39688c2ecf20Sopenharmony_ci			continue;
39698c2ecf20Sopenharmony_ci		}
39708c2ecf20Sopenharmony_ci
39718c2ecf20Sopenharmony_ci		buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, err_info.cookie);
39728c2ecf20Sopenharmony_ci		mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, err_info.cookie);
39738c2ecf20Sopenharmony_ci
39748c2ecf20Sopenharmony_ci		ar = ab->pdevs[mac_id].ar;
39758c2ecf20Sopenharmony_ci		rx_ring = &ar->dp.rx_refill_buf_ring;
39768c2ecf20Sopenharmony_ci
39778c2ecf20Sopenharmony_ci		spin_lock_bh(&rx_ring->idr_lock);
39788c2ecf20Sopenharmony_ci		msdu = idr_find(&rx_ring->bufs_idr, buf_id);
39798c2ecf20Sopenharmony_ci		if (!msdu) {
39808c2ecf20Sopenharmony_ci			ath11k_warn(ab, "frame rx with invalid buf_id %d pdev %d\n",
39818c2ecf20Sopenharmony_ci				    buf_id, mac_id);
39828c2ecf20Sopenharmony_ci			spin_unlock_bh(&rx_ring->idr_lock);
39838c2ecf20Sopenharmony_ci			continue;
39848c2ecf20Sopenharmony_ci		}
39858c2ecf20Sopenharmony_ci
39868c2ecf20Sopenharmony_ci		idr_remove(&rx_ring->bufs_idr, buf_id);
39878c2ecf20Sopenharmony_ci		spin_unlock_bh(&rx_ring->idr_lock);
39888c2ecf20Sopenharmony_ci
39898c2ecf20Sopenharmony_ci		rxcb = ATH11K_SKB_RXCB(msdu);
39908c2ecf20Sopenharmony_ci		dma_unmap_single(ab->dev, rxcb->paddr,
39918c2ecf20Sopenharmony_ci				 msdu->len + skb_tailroom(msdu),
39928c2ecf20Sopenharmony_ci				 DMA_FROM_DEVICE);
39938c2ecf20Sopenharmony_ci
39948c2ecf20Sopenharmony_ci		num_buffs_reaped[mac_id]++;
39958c2ecf20Sopenharmony_ci		total_num_buffs_reaped++;
39968c2ecf20Sopenharmony_ci		budget--;
39978c2ecf20Sopenharmony_ci
39988c2ecf20Sopenharmony_ci		if (err_info.push_reason !=
39998c2ecf20Sopenharmony_ci		    HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
40008c2ecf20Sopenharmony_ci			dev_kfree_skb_any(msdu);
40018c2ecf20Sopenharmony_ci			continue;
40028c2ecf20Sopenharmony_ci		}
40038c2ecf20Sopenharmony_ci
40048c2ecf20Sopenharmony_ci		rxcb->err_rel_src = err_info.err_rel_src;
40058c2ecf20Sopenharmony_ci		rxcb->err_code = err_info.err_code;
40068c2ecf20Sopenharmony_ci		rxcb->rx_desc = (struct hal_rx_desc *)msdu->data;
40078c2ecf20Sopenharmony_ci		__skb_queue_tail(&msdu_list[mac_id], msdu);
40088c2ecf20Sopenharmony_ci	}
40098c2ecf20Sopenharmony_ci
40108c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
40118c2ecf20Sopenharmony_ci
40128c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_ci	if (!total_num_buffs_reaped)
40158c2ecf20Sopenharmony_ci		goto done;
40168c2ecf20Sopenharmony_ci
40178c2ecf20Sopenharmony_ci	for (i = 0; i <  ab->num_radios; i++) {
40188c2ecf20Sopenharmony_ci		if (!num_buffs_reaped[i])
40198c2ecf20Sopenharmony_ci			continue;
40208c2ecf20Sopenharmony_ci
40218c2ecf20Sopenharmony_ci		ar = ab->pdevs[i].ar;
40228c2ecf20Sopenharmony_ci		rx_ring = &ar->dp.rx_refill_buf_ring;
40238c2ecf20Sopenharmony_ci
40248c2ecf20Sopenharmony_ci		ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i],
40258c2ecf20Sopenharmony_ci					   HAL_RX_BUF_RBM_SW3_BM);
40268c2ecf20Sopenharmony_ci	}
40278c2ecf20Sopenharmony_ci
40288c2ecf20Sopenharmony_ci	rcu_read_lock();
40298c2ecf20Sopenharmony_ci	for (i = 0; i <  ab->num_radios; i++) {
40308c2ecf20Sopenharmony_ci		if (!rcu_dereference(ab->pdevs_active[i])) {
40318c2ecf20Sopenharmony_ci			__skb_queue_purge(&msdu_list[i]);
40328c2ecf20Sopenharmony_ci			continue;
40338c2ecf20Sopenharmony_ci		}
40348c2ecf20Sopenharmony_ci
40358c2ecf20Sopenharmony_ci		ar = ab->pdevs[i].ar;
40368c2ecf20Sopenharmony_ci
40378c2ecf20Sopenharmony_ci		if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
40388c2ecf20Sopenharmony_ci			__skb_queue_purge(&msdu_list[i]);
40398c2ecf20Sopenharmony_ci			continue;
40408c2ecf20Sopenharmony_ci		}
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci		while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL)
40438c2ecf20Sopenharmony_ci			ath11k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]);
40448c2ecf20Sopenharmony_ci	}
40458c2ecf20Sopenharmony_ci	rcu_read_unlock();
40468c2ecf20Sopenharmony_cidone:
40478c2ecf20Sopenharmony_ci	return total_num_buffs_reaped;
40488c2ecf20Sopenharmony_ci}
40498c2ecf20Sopenharmony_ci
40508c2ecf20Sopenharmony_ciint ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget)
40518c2ecf20Sopenharmony_ci{
40528c2ecf20Sopenharmony_ci	struct ath11k *ar;
40538c2ecf20Sopenharmony_ci	struct dp_srng *err_ring;
40548c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring;
40558c2ecf20Sopenharmony_ci	struct dp_link_desc_bank *link_desc_banks = ab->dp.link_desc_banks;
40568c2ecf20Sopenharmony_ci	struct hal_srng *srng;
40578c2ecf20Sopenharmony_ci	u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC];
40588c2ecf20Sopenharmony_ci	enum hal_rx_buf_return_buf_manager rbm;
40598c2ecf20Sopenharmony_ci	enum hal_reo_entr_rxdma_ecode rxdma_err_code;
40608c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
40618c2ecf20Sopenharmony_ci	struct sk_buff *skb;
40628c2ecf20Sopenharmony_ci	struct hal_reo_entrance_ring *entr_ring;
40638c2ecf20Sopenharmony_ci	void *desc;
40648c2ecf20Sopenharmony_ci	int num_buf_freed = 0;
40658c2ecf20Sopenharmony_ci	int quota = budget;
40668c2ecf20Sopenharmony_ci	dma_addr_t paddr;
40678c2ecf20Sopenharmony_ci	u32 desc_bank;
40688c2ecf20Sopenharmony_ci	void *link_desc_va;
40698c2ecf20Sopenharmony_ci	int num_msdus;
40708c2ecf20Sopenharmony_ci	int i;
40718c2ecf20Sopenharmony_ci	int buf_id;
40728c2ecf20Sopenharmony_ci
40738c2ecf20Sopenharmony_ci	ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar;
40748c2ecf20Sopenharmony_ci	err_ring = &ar->dp.rxdma_err_dst_ring[ath11k_hw_mac_id_to_srng_id(&ab->hw_params,
40758c2ecf20Sopenharmony_ci									  mac_id)];
40768c2ecf20Sopenharmony_ci	rx_ring = &ar->dp.rx_refill_buf_ring;
40778c2ecf20Sopenharmony_ci
40788c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[err_ring->ring_id];
40798c2ecf20Sopenharmony_ci
40808c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
40818c2ecf20Sopenharmony_ci
40828c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
40838c2ecf20Sopenharmony_ci
40848c2ecf20Sopenharmony_ci	while (quota-- &&
40858c2ecf20Sopenharmony_ci	       (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
40868c2ecf20Sopenharmony_ci		ath11k_hal_rx_reo_ent_paddr_get(ab, desc, &paddr, &desc_bank);
40878c2ecf20Sopenharmony_ci
40888c2ecf20Sopenharmony_ci		entr_ring = (struct hal_reo_entrance_ring *)desc;
40898c2ecf20Sopenharmony_ci		rxdma_err_code =
40908c2ecf20Sopenharmony_ci			FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE,
40918c2ecf20Sopenharmony_ci				  entr_ring->info1);
40928c2ecf20Sopenharmony_ci		ab->soc_stats.rxdma_error[rxdma_err_code]++;
40938c2ecf20Sopenharmony_ci
40948c2ecf20Sopenharmony_ci		link_desc_va = link_desc_banks[desc_bank].vaddr +
40958c2ecf20Sopenharmony_ci			       (paddr - link_desc_banks[desc_bank].paddr);
40968c2ecf20Sopenharmony_ci		ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus,
40978c2ecf20Sopenharmony_ci						 msdu_cookies, &rbm);
40988c2ecf20Sopenharmony_ci
40998c2ecf20Sopenharmony_ci		for (i = 0; i < num_msdus; i++) {
41008c2ecf20Sopenharmony_ci			buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
41018c2ecf20Sopenharmony_ci					   msdu_cookies[i]);
41028c2ecf20Sopenharmony_ci
41038c2ecf20Sopenharmony_ci			spin_lock_bh(&rx_ring->idr_lock);
41048c2ecf20Sopenharmony_ci			skb = idr_find(&rx_ring->bufs_idr, buf_id);
41058c2ecf20Sopenharmony_ci			if (!skb) {
41068c2ecf20Sopenharmony_ci				ath11k_warn(ab, "rxdma error with invalid buf_id %d\n",
41078c2ecf20Sopenharmony_ci					    buf_id);
41088c2ecf20Sopenharmony_ci				spin_unlock_bh(&rx_ring->idr_lock);
41098c2ecf20Sopenharmony_ci				continue;
41108c2ecf20Sopenharmony_ci			}
41118c2ecf20Sopenharmony_ci
41128c2ecf20Sopenharmony_ci			idr_remove(&rx_ring->bufs_idr, buf_id);
41138c2ecf20Sopenharmony_ci			spin_unlock_bh(&rx_ring->idr_lock);
41148c2ecf20Sopenharmony_ci
41158c2ecf20Sopenharmony_ci			rxcb = ATH11K_SKB_RXCB(skb);
41168c2ecf20Sopenharmony_ci			dma_unmap_single(ab->dev, rxcb->paddr,
41178c2ecf20Sopenharmony_ci					 skb->len + skb_tailroom(skb),
41188c2ecf20Sopenharmony_ci					 DMA_FROM_DEVICE);
41198c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
41208c2ecf20Sopenharmony_ci
41218c2ecf20Sopenharmony_ci			num_buf_freed++;
41228c2ecf20Sopenharmony_ci		}
41238c2ecf20Sopenharmony_ci
41248c2ecf20Sopenharmony_ci		ath11k_dp_rx_link_desc_return(ab, desc,
41258c2ecf20Sopenharmony_ci					      HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
41268c2ecf20Sopenharmony_ci	}
41278c2ecf20Sopenharmony_ci
41288c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
41318c2ecf20Sopenharmony_ci
41328c2ecf20Sopenharmony_ci	if (num_buf_freed)
41338c2ecf20Sopenharmony_ci		ath11k_dp_rxbufs_replenish(ab, mac_id, rx_ring, num_buf_freed,
41348c2ecf20Sopenharmony_ci					   HAL_RX_BUF_RBM_SW3_BM);
41358c2ecf20Sopenharmony_ci
41368c2ecf20Sopenharmony_ci	return budget - quota;
41378c2ecf20Sopenharmony_ci}
41388c2ecf20Sopenharmony_ci
41398c2ecf20Sopenharmony_civoid ath11k_dp_process_reo_status(struct ath11k_base *ab)
41408c2ecf20Sopenharmony_ci{
41418c2ecf20Sopenharmony_ci	struct ath11k_dp *dp = &ab->dp;
41428c2ecf20Sopenharmony_ci	struct hal_srng *srng;
41438c2ecf20Sopenharmony_ci	struct dp_reo_cmd *cmd, *tmp;
41448c2ecf20Sopenharmony_ci	bool found = false;
41458c2ecf20Sopenharmony_ci	u32 *reo_desc;
41468c2ecf20Sopenharmony_ci	u16 tag;
41478c2ecf20Sopenharmony_ci	struct hal_reo_status reo_status;
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	srng = &ab->hal.srng_list[dp->reo_status_ring.ring_id];
41508c2ecf20Sopenharmony_ci
41518c2ecf20Sopenharmony_ci	memset(&reo_status, 0, sizeof(reo_status));
41528c2ecf20Sopenharmony_ci
41538c2ecf20Sopenharmony_ci	spin_lock_bh(&srng->lock);
41548c2ecf20Sopenharmony_ci
41558c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ab, srng);
41568c2ecf20Sopenharmony_ci
41578c2ecf20Sopenharmony_ci	while ((reo_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
41588c2ecf20Sopenharmony_ci		tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, *reo_desc);
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci		switch (tag) {
41618c2ecf20Sopenharmony_ci		case HAL_REO_GET_QUEUE_STATS_STATUS:
41628c2ecf20Sopenharmony_ci			ath11k_hal_reo_status_queue_stats(ab, reo_desc,
41638c2ecf20Sopenharmony_ci							  &reo_status);
41648c2ecf20Sopenharmony_ci			break;
41658c2ecf20Sopenharmony_ci		case HAL_REO_FLUSH_QUEUE_STATUS:
41668c2ecf20Sopenharmony_ci			ath11k_hal_reo_flush_queue_status(ab, reo_desc,
41678c2ecf20Sopenharmony_ci							  &reo_status);
41688c2ecf20Sopenharmony_ci			break;
41698c2ecf20Sopenharmony_ci		case HAL_REO_FLUSH_CACHE_STATUS:
41708c2ecf20Sopenharmony_ci			ath11k_hal_reo_flush_cache_status(ab, reo_desc,
41718c2ecf20Sopenharmony_ci							  &reo_status);
41728c2ecf20Sopenharmony_ci			break;
41738c2ecf20Sopenharmony_ci		case HAL_REO_UNBLOCK_CACHE_STATUS:
41748c2ecf20Sopenharmony_ci			ath11k_hal_reo_unblk_cache_status(ab, reo_desc,
41758c2ecf20Sopenharmony_ci							  &reo_status);
41768c2ecf20Sopenharmony_ci			break;
41778c2ecf20Sopenharmony_ci		case HAL_REO_FLUSH_TIMEOUT_LIST_STATUS:
41788c2ecf20Sopenharmony_ci			ath11k_hal_reo_flush_timeout_list_status(ab, reo_desc,
41798c2ecf20Sopenharmony_ci								 &reo_status);
41808c2ecf20Sopenharmony_ci			break;
41818c2ecf20Sopenharmony_ci		case HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS:
41828c2ecf20Sopenharmony_ci			ath11k_hal_reo_desc_thresh_reached_status(ab, reo_desc,
41838c2ecf20Sopenharmony_ci								  &reo_status);
41848c2ecf20Sopenharmony_ci			break;
41858c2ecf20Sopenharmony_ci		case HAL_REO_UPDATE_RX_REO_QUEUE_STATUS:
41868c2ecf20Sopenharmony_ci			ath11k_hal_reo_update_rx_reo_queue_status(ab, reo_desc,
41878c2ecf20Sopenharmony_ci								  &reo_status);
41888c2ecf20Sopenharmony_ci			break;
41898c2ecf20Sopenharmony_ci		default:
41908c2ecf20Sopenharmony_ci			ath11k_warn(ab, "Unknown reo status type %d\n", tag);
41918c2ecf20Sopenharmony_ci			continue;
41928c2ecf20Sopenharmony_ci		}
41938c2ecf20Sopenharmony_ci
41948c2ecf20Sopenharmony_ci		spin_lock_bh(&dp->reo_cmd_lock);
41958c2ecf20Sopenharmony_ci		list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
41968c2ecf20Sopenharmony_ci			if (reo_status.uniform_hdr.cmd_num == cmd->cmd_num) {
41978c2ecf20Sopenharmony_ci				found = true;
41988c2ecf20Sopenharmony_ci				list_del(&cmd->list);
41998c2ecf20Sopenharmony_ci				break;
42008c2ecf20Sopenharmony_ci			}
42018c2ecf20Sopenharmony_ci		}
42028c2ecf20Sopenharmony_ci		spin_unlock_bh(&dp->reo_cmd_lock);
42038c2ecf20Sopenharmony_ci
42048c2ecf20Sopenharmony_ci		if (found) {
42058c2ecf20Sopenharmony_ci			cmd->handler(dp, (void *)&cmd->data,
42068c2ecf20Sopenharmony_ci				     reo_status.uniform_hdr.cmd_status);
42078c2ecf20Sopenharmony_ci			kfree(cmd);
42088c2ecf20Sopenharmony_ci		}
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci		found = false;
42118c2ecf20Sopenharmony_ci	}
42128c2ecf20Sopenharmony_ci
42138c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ab, srng);
42148c2ecf20Sopenharmony_ci
42158c2ecf20Sopenharmony_ci	spin_unlock_bh(&srng->lock);
42168c2ecf20Sopenharmony_ci}
42178c2ecf20Sopenharmony_ci
42188c2ecf20Sopenharmony_civoid ath11k_dp_rx_pdev_free(struct ath11k_base *ab, int mac_id)
42198c2ecf20Sopenharmony_ci{
42208c2ecf20Sopenharmony_ci	struct ath11k *ar = ab->pdevs[mac_id].ar;
42218c2ecf20Sopenharmony_ci
42228c2ecf20Sopenharmony_ci	ath11k_dp_rx_pdev_srng_free(ar);
42238c2ecf20Sopenharmony_ci	ath11k_dp_rxdma_pdev_buf_free(ar);
42248c2ecf20Sopenharmony_ci}
42258c2ecf20Sopenharmony_ci
42268c2ecf20Sopenharmony_ciint ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id)
42278c2ecf20Sopenharmony_ci{
42288c2ecf20Sopenharmony_ci	struct ath11k *ar = ab->pdevs[mac_id].ar;
42298c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
42308c2ecf20Sopenharmony_ci	u32 ring_id;
42318c2ecf20Sopenharmony_ci	int i;
42328c2ecf20Sopenharmony_ci	int ret;
42338c2ecf20Sopenharmony_ci
42348c2ecf20Sopenharmony_ci	ret = ath11k_dp_rx_pdev_srng_alloc(ar);
42358c2ecf20Sopenharmony_ci	if (ret) {
42368c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to setup rx srngs\n");
42378c2ecf20Sopenharmony_ci		return ret;
42388c2ecf20Sopenharmony_ci	}
42398c2ecf20Sopenharmony_ci
42408c2ecf20Sopenharmony_ci	ret = ath11k_dp_rxdma_pdev_buf_setup(ar);
42418c2ecf20Sopenharmony_ci	if (ret) {
42428c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to setup rxdma ring\n");
42438c2ecf20Sopenharmony_ci		return ret;
42448c2ecf20Sopenharmony_ci	}
42458c2ecf20Sopenharmony_ci
42468c2ecf20Sopenharmony_ci	ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id;
42478c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_BUF);
42488c2ecf20Sopenharmony_ci	if (ret) {
42498c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to configure rx_refill_buf_ring %d\n",
42508c2ecf20Sopenharmony_ci			    ret);
42518c2ecf20Sopenharmony_ci		return ret;
42528c2ecf20Sopenharmony_ci	}
42538c2ecf20Sopenharmony_ci
42548c2ecf20Sopenharmony_ci	if (ab->hw_params.rx_mac_buf_ring) {
42558c2ecf20Sopenharmony_ci		for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
42568c2ecf20Sopenharmony_ci			ring_id = dp->rx_mac_buf_ring[i].ring_id;
42578c2ecf20Sopenharmony_ci			ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id,
42588c2ecf20Sopenharmony_ci							  mac_id + i, HAL_RXDMA_BUF);
42598c2ecf20Sopenharmony_ci			if (ret) {
42608c2ecf20Sopenharmony_ci				ath11k_warn(ab, "failed to configure rx_mac_buf_ring%d %d\n",
42618c2ecf20Sopenharmony_ci					    i, ret);
42628c2ecf20Sopenharmony_ci				return ret;
42638c2ecf20Sopenharmony_ci			}
42648c2ecf20Sopenharmony_ci		}
42658c2ecf20Sopenharmony_ci	}
42668c2ecf20Sopenharmony_ci
42678c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
42688c2ecf20Sopenharmony_ci		ring_id = dp->rxdma_err_dst_ring[i].ring_id;
42698c2ecf20Sopenharmony_ci		ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id,
42708c2ecf20Sopenharmony_ci						  mac_id + i, HAL_RXDMA_DST);
42718c2ecf20Sopenharmony_ci		if (ret) {
42728c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to configure rxdma_err_dest_ring%d %d\n",
42738c2ecf20Sopenharmony_ci				    i, ret);
42748c2ecf20Sopenharmony_ci			return ret;
42758c2ecf20Sopenharmony_ci		}
42768c2ecf20Sopenharmony_ci	}
42778c2ecf20Sopenharmony_ci
42788c2ecf20Sopenharmony_ci	if (!ab->hw_params.rxdma1_enable)
42798c2ecf20Sopenharmony_ci		goto config_refill_ring;
42808c2ecf20Sopenharmony_ci
42818c2ecf20Sopenharmony_ci	ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
42828c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id,
42838c2ecf20Sopenharmony_ci					  mac_id, HAL_RXDMA_MONITOR_BUF);
42848c2ecf20Sopenharmony_ci	if (ret) {
42858c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to configure rxdma_mon_buf_ring %d\n",
42868c2ecf20Sopenharmony_ci			    ret);
42878c2ecf20Sopenharmony_ci		return ret;
42888c2ecf20Sopenharmony_ci	}
42898c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_htt_srng_setup(ab,
42908c2ecf20Sopenharmony_ci					  dp->rxdma_mon_dst_ring.ring_id,
42918c2ecf20Sopenharmony_ci					  mac_id, HAL_RXDMA_MONITOR_DST);
42928c2ecf20Sopenharmony_ci	if (ret) {
42938c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n",
42948c2ecf20Sopenharmony_ci			    ret);
42958c2ecf20Sopenharmony_ci		return ret;
42968c2ecf20Sopenharmony_ci	}
42978c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_htt_srng_setup(ab,
42988c2ecf20Sopenharmony_ci					  dp->rxdma_mon_desc_ring.ring_id,
42998c2ecf20Sopenharmony_ci					  mac_id, HAL_RXDMA_MONITOR_DESC);
43008c2ecf20Sopenharmony_ci	if (ret) {
43018c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n",
43028c2ecf20Sopenharmony_ci			    ret);
43038c2ecf20Sopenharmony_ci		return ret;
43048c2ecf20Sopenharmony_ci	}
43058c2ecf20Sopenharmony_ci
43068c2ecf20Sopenharmony_ciconfig_refill_ring:
43078c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
43088c2ecf20Sopenharmony_ci		ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
43098c2ecf20Sopenharmony_ci		ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i,
43108c2ecf20Sopenharmony_ci						  HAL_RXDMA_MONITOR_STATUS);
43118c2ecf20Sopenharmony_ci		if (ret) {
43128c2ecf20Sopenharmony_ci			ath11k_warn(ab,
43138c2ecf20Sopenharmony_ci				    "failed to configure mon_status_refill_ring%d %d\n",
43148c2ecf20Sopenharmony_ci				    i, ret);
43158c2ecf20Sopenharmony_ci			return ret;
43168c2ecf20Sopenharmony_ci		}
43178c2ecf20Sopenharmony_ci	}
43188c2ecf20Sopenharmony_ci
43198c2ecf20Sopenharmony_ci	return 0;
43208c2ecf20Sopenharmony_ci}
43218c2ecf20Sopenharmony_ci
43228c2ecf20Sopenharmony_cistatic void ath11k_dp_mon_set_frag_len(u32 *total_len, u32 *frag_len)
43238c2ecf20Sopenharmony_ci{
43248c2ecf20Sopenharmony_ci	if (*total_len >= (DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc))) {
43258c2ecf20Sopenharmony_ci		*frag_len = DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc);
43268c2ecf20Sopenharmony_ci		*total_len -= *frag_len;
43278c2ecf20Sopenharmony_ci	} else {
43288c2ecf20Sopenharmony_ci		*frag_len = *total_len;
43298c2ecf20Sopenharmony_ci		*total_len = 0;
43308c2ecf20Sopenharmony_ci	}
43318c2ecf20Sopenharmony_ci}
43328c2ecf20Sopenharmony_ci
43338c2ecf20Sopenharmony_cistatic
43348c2ecf20Sopenharmony_ciint ath11k_dp_rx_monitor_link_desc_return(struct ath11k *ar,
43358c2ecf20Sopenharmony_ci					  void *p_last_buf_addr_info,
43368c2ecf20Sopenharmony_ci					  u8 mac_id)
43378c2ecf20Sopenharmony_ci{
43388c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
43398c2ecf20Sopenharmony_ci	struct dp_srng *dp_srng;
43408c2ecf20Sopenharmony_ci	void *hal_srng;
43418c2ecf20Sopenharmony_ci	void *src_srng_desc;
43428c2ecf20Sopenharmony_ci	int ret = 0;
43438c2ecf20Sopenharmony_ci
43448c2ecf20Sopenharmony_ci	if (ar->ab->hw_params.rxdma1_enable) {
43458c2ecf20Sopenharmony_ci		dp_srng = &dp->rxdma_mon_desc_ring;
43468c2ecf20Sopenharmony_ci		hal_srng = &ar->ab->hal.srng_list[dp_srng->ring_id];
43478c2ecf20Sopenharmony_ci	} else {
43488c2ecf20Sopenharmony_ci		dp_srng = &ar->ab->dp.wbm_desc_rel_ring;
43498c2ecf20Sopenharmony_ci		hal_srng = &ar->ab->hal.srng_list[dp_srng->ring_id];
43508c2ecf20Sopenharmony_ci	}
43518c2ecf20Sopenharmony_ci
43528c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ar->ab, hal_srng);
43538c2ecf20Sopenharmony_ci
43548c2ecf20Sopenharmony_ci	src_srng_desc = ath11k_hal_srng_src_get_next_entry(ar->ab, hal_srng);
43558c2ecf20Sopenharmony_ci
43568c2ecf20Sopenharmony_ci	if (src_srng_desc) {
43578c2ecf20Sopenharmony_ci		struct ath11k_buffer_addr *src_desc =
43588c2ecf20Sopenharmony_ci				(struct ath11k_buffer_addr *)src_srng_desc;
43598c2ecf20Sopenharmony_ci
43608c2ecf20Sopenharmony_ci		*src_desc = *((struct ath11k_buffer_addr *)p_last_buf_addr_info);
43618c2ecf20Sopenharmony_ci	} else {
43628c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
43638c2ecf20Sopenharmony_ci			   "Monitor Link Desc Ring %d Full", mac_id);
43648c2ecf20Sopenharmony_ci		ret = -ENOMEM;
43658c2ecf20Sopenharmony_ci	}
43668c2ecf20Sopenharmony_ci
43678c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ar->ab, hal_srng);
43688c2ecf20Sopenharmony_ci	return ret;
43698c2ecf20Sopenharmony_ci}
43708c2ecf20Sopenharmony_ci
43718c2ecf20Sopenharmony_cistatic
43728c2ecf20Sopenharmony_civoid ath11k_dp_rx_mon_next_link_desc_get(void *rx_msdu_link_desc,
43738c2ecf20Sopenharmony_ci					 dma_addr_t *paddr, u32 *sw_cookie,
43748c2ecf20Sopenharmony_ci					 u8 *rbm,
43758c2ecf20Sopenharmony_ci					 void **pp_buf_addr_info)
43768c2ecf20Sopenharmony_ci{
43778c2ecf20Sopenharmony_ci	struct hal_rx_msdu_link *msdu_link =
43788c2ecf20Sopenharmony_ci			(struct hal_rx_msdu_link *)rx_msdu_link_desc;
43798c2ecf20Sopenharmony_ci	struct ath11k_buffer_addr *buf_addr_info;
43808c2ecf20Sopenharmony_ci
43818c2ecf20Sopenharmony_ci	buf_addr_info = (struct ath11k_buffer_addr *)&msdu_link->buf_addr_info;
43828c2ecf20Sopenharmony_ci
43838c2ecf20Sopenharmony_ci	ath11k_hal_rx_buf_addr_info_get(buf_addr_info, paddr, sw_cookie, rbm);
43848c2ecf20Sopenharmony_ci
43858c2ecf20Sopenharmony_ci	*pp_buf_addr_info = (void *)buf_addr_info;
43868c2ecf20Sopenharmony_ci}
43878c2ecf20Sopenharmony_ci
43888c2ecf20Sopenharmony_cistatic int ath11k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len)
43898c2ecf20Sopenharmony_ci{
43908c2ecf20Sopenharmony_ci	if (skb->len > len) {
43918c2ecf20Sopenharmony_ci		skb_trim(skb, len);
43928c2ecf20Sopenharmony_ci	} else {
43938c2ecf20Sopenharmony_ci		if (skb_tailroom(skb) < len - skb->len) {
43948c2ecf20Sopenharmony_ci			if ((pskb_expand_head(skb, 0,
43958c2ecf20Sopenharmony_ci					      len - skb->len - skb_tailroom(skb),
43968c2ecf20Sopenharmony_ci					      GFP_ATOMIC))) {
43978c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb);
43988c2ecf20Sopenharmony_ci				return -ENOMEM;
43998c2ecf20Sopenharmony_ci			}
44008c2ecf20Sopenharmony_ci		}
44018c2ecf20Sopenharmony_ci		skb_put(skb, (len - skb->len));
44028c2ecf20Sopenharmony_ci	}
44038c2ecf20Sopenharmony_ci	return 0;
44048c2ecf20Sopenharmony_ci}
44058c2ecf20Sopenharmony_ci
44068c2ecf20Sopenharmony_cistatic void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
44078c2ecf20Sopenharmony_ci					void *msdu_link_desc,
44088c2ecf20Sopenharmony_ci					struct hal_rx_msdu_list *msdu_list,
44098c2ecf20Sopenharmony_ci					u16 *num_msdus)
44108c2ecf20Sopenharmony_ci{
44118c2ecf20Sopenharmony_ci	struct hal_rx_msdu_details *msdu_details = NULL;
44128c2ecf20Sopenharmony_ci	struct rx_msdu_desc *msdu_desc_info = NULL;
44138c2ecf20Sopenharmony_ci	struct hal_rx_msdu_link *msdu_link = NULL;
44148c2ecf20Sopenharmony_ci	int i;
44158c2ecf20Sopenharmony_ci	u32 last = FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1);
44168c2ecf20Sopenharmony_ci	u32 first = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1);
44178c2ecf20Sopenharmony_ci	u8  tmp  = 0;
44188c2ecf20Sopenharmony_ci
44198c2ecf20Sopenharmony_ci	msdu_link = (struct hal_rx_msdu_link *)msdu_link_desc;
44208c2ecf20Sopenharmony_ci	msdu_details = &msdu_link->msdu_link[0];
44218c2ecf20Sopenharmony_ci
44228c2ecf20Sopenharmony_ci	for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
44238c2ecf20Sopenharmony_ci		if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
44248c2ecf20Sopenharmony_ci			      msdu_details[i].buf_addr_info.info0) == 0) {
44258c2ecf20Sopenharmony_ci			msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;
44268c2ecf20Sopenharmony_ci			msdu_desc_info->info0 |= last;
44278c2ecf20Sopenharmony_ci			;
44288c2ecf20Sopenharmony_ci			break;
44298c2ecf20Sopenharmony_ci		}
44308c2ecf20Sopenharmony_ci		msdu_desc_info = &msdu_details[i].rx_msdu_info;
44318c2ecf20Sopenharmony_ci
44328c2ecf20Sopenharmony_ci		if (!i)
44338c2ecf20Sopenharmony_ci			msdu_desc_info->info0 |= first;
44348c2ecf20Sopenharmony_ci		else if (i == (HAL_RX_NUM_MSDU_DESC - 1))
44358c2ecf20Sopenharmony_ci			msdu_desc_info->info0 |= last;
44368c2ecf20Sopenharmony_ci		msdu_list->msdu_info[i].msdu_flags = msdu_desc_info->info0;
44378c2ecf20Sopenharmony_ci		msdu_list->msdu_info[i].msdu_len =
44388c2ecf20Sopenharmony_ci			 HAL_RX_MSDU_PKT_LENGTH_GET(msdu_desc_info->info0);
44398c2ecf20Sopenharmony_ci		msdu_list->sw_cookie[i] =
44408c2ecf20Sopenharmony_ci			FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
44418c2ecf20Sopenharmony_ci				  msdu_details[i].buf_addr_info.info1);
44428c2ecf20Sopenharmony_ci		tmp = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR,
44438c2ecf20Sopenharmony_ci				msdu_details[i].buf_addr_info.info1);
44448c2ecf20Sopenharmony_ci		msdu_list->rbm[i] = tmp;
44458c2ecf20Sopenharmony_ci	}
44468c2ecf20Sopenharmony_ci	*num_msdus = i;
44478c2ecf20Sopenharmony_ci}
44488c2ecf20Sopenharmony_ci
44498c2ecf20Sopenharmony_cistatic u32 ath11k_dp_rx_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id,
44508c2ecf20Sopenharmony_ci					u32 *rx_bufs_used)
44518c2ecf20Sopenharmony_ci{
44528c2ecf20Sopenharmony_ci	u32 ret = 0;
44538c2ecf20Sopenharmony_ci
44548c2ecf20Sopenharmony_ci	if ((*ppdu_id < msdu_ppdu_id) &&
44558c2ecf20Sopenharmony_ci	    ((msdu_ppdu_id - *ppdu_id) < DP_NOT_PPDU_ID_WRAP_AROUND)) {
44568c2ecf20Sopenharmony_ci		*ppdu_id = msdu_ppdu_id;
44578c2ecf20Sopenharmony_ci		ret = msdu_ppdu_id;
44588c2ecf20Sopenharmony_ci	} else if ((*ppdu_id > msdu_ppdu_id) &&
44598c2ecf20Sopenharmony_ci		((*ppdu_id - msdu_ppdu_id) > DP_NOT_PPDU_ID_WRAP_AROUND)) {
44608c2ecf20Sopenharmony_ci		/* mon_dst is behind than mon_status
44618c2ecf20Sopenharmony_ci		 * skip dst_ring and free it
44628c2ecf20Sopenharmony_ci		 */
44638c2ecf20Sopenharmony_ci		*rx_bufs_used += 1;
44648c2ecf20Sopenharmony_ci		*ppdu_id = msdu_ppdu_id;
44658c2ecf20Sopenharmony_ci		ret = msdu_ppdu_id;
44668c2ecf20Sopenharmony_ci	}
44678c2ecf20Sopenharmony_ci	return ret;
44688c2ecf20Sopenharmony_ci}
44698c2ecf20Sopenharmony_ci
44708c2ecf20Sopenharmony_cistatic void ath11k_dp_mon_get_buf_len(struct hal_rx_msdu_desc_info *info,
44718c2ecf20Sopenharmony_ci				      bool *is_frag, u32 *total_len,
44728c2ecf20Sopenharmony_ci				      u32 *frag_len, u32 *msdu_cnt)
44738c2ecf20Sopenharmony_ci{
44748c2ecf20Sopenharmony_ci	if (info->msdu_flags & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION) {
44758c2ecf20Sopenharmony_ci		if (!*is_frag) {
44768c2ecf20Sopenharmony_ci			*total_len = info->msdu_len;
44778c2ecf20Sopenharmony_ci			*is_frag = true;
44788c2ecf20Sopenharmony_ci		}
44798c2ecf20Sopenharmony_ci		ath11k_dp_mon_set_frag_len(total_len,
44808c2ecf20Sopenharmony_ci					   frag_len);
44818c2ecf20Sopenharmony_ci	} else {
44828c2ecf20Sopenharmony_ci		if (*is_frag) {
44838c2ecf20Sopenharmony_ci			ath11k_dp_mon_set_frag_len(total_len,
44848c2ecf20Sopenharmony_ci						   frag_len);
44858c2ecf20Sopenharmony_ci		} else {
44868c2ecf20Sopenharmony_ci			*frag_len = info->msdu_len;
44878c2ecf20Sopenharmony_ci		}
44888c2ecf20Sopenharmony_ci		*is_frag = false;
44898c2ecf20Sopenharmony_ci		*msdu_cnt -= 1;
44908c2ecf20Sopenharmony_ci	}
44918c2ecf20Sopenharmony_ci}
44928c2ecf20Sopenharmony_ci
44938c2ecf20Sopenharmony_cistatic u32
44948c2ecf20Sopenharmony_ciath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id,
44958c2ecf20Sopenharmony_ci			  void *ring_entry, struct sk_buff **head_msdu,
44968c2ecf20Sopenharmony_ci			  struct sk_buff **tail_msdu, u32 *npackets,
44978c2ecf20Sopenharmony_ci			  u32 *ppdu_id)
44988c2ecf20Sopenharmony_ci{
44998c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
45008c2ecf20Sopenharmony_ci	struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
45018c2ecf20Sopenharmony_ci	struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring;
45028c2ecf20Sopenharmony_ci	struct sk_buff *msdu = NULL, *last = NULL;
45038c2ecf20Sopenharmony_ci	struct hal_rx_msdu_list msdu_list;
45048c2ecf20Sopenharmony_ci	void *p_buf_addr_info, *p_last_buf_addr_info;
45058c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc;
45068c2ecf20Sopenharmony_ci	void *rx_msdu_link_desc;
45078c2ecf20Sopenharmony_ci	dma_addr_t paddr;
45088c2ecf20Sopenharmony_ci	u16 num_msdus = 0;
45098c2ecf20Sopenharmony_ci	u32 rx_buf_size, rx_pkt_offset, sw_cookie;
45108c2ecf20Sopenharmony_ci	u32 rx_bufs_used = 0, i = 0;
45118c2ecf20Sopenharmony_ci	u32 msdu_ppdu_id = 0, msdu_cnt = 0;
45128c2ecf20Sopenharmony_ci	u32 total_len = 0, frag_len = 0;
45138c2ecf20Sopenharmony_ci	bool is_frag, is_first_msdu;
45148c2ecf20Sopenharmony_ci	bool drop_mpdu = false;
45158c2ecf20Sopenharmony_ci	struct ath11k_skb_rxcb *rxcb;
45168c2ecf20Sopenharmony_ci	struct hal_reo_entrance_ring *ent_desc =
45178c2ecf20Sopenharmony_ci			(struct hal_reo_entrance_ring *)ring_entry;
45188c2ecf20Sopenharmony_ci	int buf_id;
45198c2ecf20Sopenharmony_ci	u32 rx_link_buf_info[2];
45208c2ecf20Sopenharmony_ci	u8 rbm;
45218c2ecf20Sopenharmony_ci
45228c2ecf20Sopenharmony_ci	if (!ar->ab->hw_params.rxdma1_enable)
45238c2ecf20Sopenharmony_ci		rx_ring = &dp->rx_refill_buf_ring;
45248c2ecf20Sopenharmony_ci
45258c2ecf20Sopenharmony_ci	ath11k_hal_rx_reo_ent_buf_paddr_get(ring_entry, &paddr,
45268c2ecf20Sopenharmony_ci					    &sw_cookie,
45278c2ecf20Sopenharmony_ci					    &p_last_buf_addr_info, &rbm,
45288c2ecf20Sopenharmony_ci					    &msdu_cnt);
45298c2ecf20Sopenharmony_ci
45308c2ecf20Sopenharmony_ci	if (FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_PUSH_REASON,
45318c2ecf20Sopenharmony_ci		      ent_desc->info1) ==
45328c2ecf20Sopenharmony_ci		      HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
45338c2ecf20Sopenharmony_ci		u8 rxdma_err =
45348c2ecf20Sopenharmony_ci			FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE,
45358c2ecf20Sopenharmony_ci				  ent_desc->info1);
45368c2ecf20Sopenharmony_ci		if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR ||
45378c2ecf20Sopenharmony_ci		    rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR ||
45388c2ecf20Sopenharmony_ci		    rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) {
45398c2ecf20Sopenharmony_ci			drop_mpdu = true;
45408c2ecf20Sopenharmony_ci			pmon->rx_mon_stats.dest_mpdu_drop++;
45418c2ecf20Sopenharmony_ci		}
45428c2ecf20Sopenharmony_ci	}
45438c2ecf20Sopenharmony_ci
45448c2ecf20Sopenharmony_ci	is_frag = false;
45458c2ecf20Sopenharmony_ci	is_first_msdu = true;
45468c2ecf20Sopenharmony_ci
45478c2ecf20Sopenharmony_ci	do {
45488c2ecf20Sopenharmony_ci		if (pmon->mon_last_linkdesc_paddr == paddr) {
45498c2ecf20Sopenharmony_ci			pmon->rx_mon_stats.dup_mon_linkdesc_cnt++;
45508c2ecf20Sopenharmony_ci			return rx_bufs_used;
45518c2ecf20Sopenharmony_ci		}
45528c2ecf20Sopenharmony_ci
45538c2ecf20Sopenharmony_ci		if (ar->ab->hw_params.rxdma1_enable)
45548c2ecf20Sopenharmony_ci			rx_msdu_link_desc =
45558c2ecf20Sopenharmony_ci				(void *)pmon->link_desc_banks[sw_cookie].vaddr +
45568c2ecf20Sopenharmony_ci				(paddr - pmon->link_desc_banks[sw_cookie].paddr);
45578c2ecf20Sopenharmony_ci		else
45588c2ecf20Sopenharmony_ci			rx_msdu_link_desc =
45598c2ecf20Sopenharmony_ci				(void *)ar->ab->dp.link_desc_banks[sw_cookie].vaddr +
45608c2ecf20Sopenharmony_ci				(paddr - ar->ab->dp.link_desc_banks[sw_cookie].paddr);
45618c2ecf20Sopenharmony_ci
45628c2ecf20Sopenharmony_ci		ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list,
45638c2ecf20Sopenharmony_ci					    &num_msdus);
45648c2ecf20Sopenharmony_ci
45658c2ecf20Sopenharmony_ci		for (i = 0; i < num_msdus; i++) {
45668c2ecf20Sopenharmony_ci			u32 l2_hdr_offset;
45678c2ecf20Sopenharmony_ci
45688c2ecf20Sopenharmony_ci			if (pmon->mon_last_buf_cookie == msdu_list.sw_cookie[i]) {
45698c2ecf20Sopenharmony_ci				ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
45708c2ecf20Sopenharmony_ci					   "i %d last_cookie %d is same\n",
45718c2ecf20Sopenharmony_ci					   i, pmon->mon_last_buf_cookie);
45728c2ecf20Sopenharmony_ci				drop_mpdu = true;
45738c2ecf20Sopenharmony_ci				pmon->rx_mon_stats.dup_mon_buf_cnt++;
45748c2ecf20Sopenharmony_ci				continue;
45758c2ecf20Sopenharmony_ci			}
45768c2ecf20Sopenharmony_ci			buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
45778c2ecf20Sopenharmony_ci					   msdu_list.sw_cookie[i]);
45788c2ecf20Sopenharmony_ci
45798c2ecf20Sopenharmony_ci			spin_lock_bh(&rx_ring->idr_lock);
45808c2ecf20Sopenharmony_ci			msdu = idr_find(&rx_ring->bufs_idr, buf_id);
45818c2ecf20Sopenharmony_ci			spin_unlock_bh(&rx_ring->idr_lock);
45828c2ecf20Sopenharmony_ci			if (!msdu) {
45838c2ecf20Sopenharmony_ci				ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
45848c2ecf20Sopenharmony_ci					   "msdu_pop: invalid buf_id %d\n", buf_id);
45858c2ecf20Sopenharmony_ci				break;
45868c2ecf20Sopenharmony_ci			}
45878c2ecf20Sopenharmony_ci			rxcb = ATH11K_SKB_RXCB(msdu);
45888c2ecf20Sopenharmony_ci			if (!rxcb->unmapped) {
45898c2ecf20Sopenharmony_ci				dma_unmap_single(ar->ab->dev, rxcb->paddr,
45908c2ecf20Sopenharmony_ci						 msdu->len +
45918c2ecf20Sopenharmony_ci						 skb_tailroom(msdu),
45928c2ecf20Sopenharmony_ci						 DMA_FROM_DEVICE);
45938c2ecf20Sopenharmony_ci				rxcb->unmapped = 1;
45948c2ecf20Sopenharmony_ci			}
45958c2ecf20Sopenharmony_ci			if (drop_mpdu) {
45968c2ecf20Sopenharmony_ci				ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
45978c2ecf20Sopenharmony_ci					   "i %d drop msdu %p *ppdu_id %x\n",
45988c2ecf20Sopenharmony_ci					   i, msdu, *ppdu_id);
45998c2ecf20Sopenharmony_ci				dev_kfree_skb_any(msdu);
46008c2ecf20Sopenharmony_ci				msdu = NULL;
46018c2ecf20Sopenharmony_ci				goto next_msdu;
46028c2ecf20Sopenharmony_ci			}
46038c2ecf20Sopenharmony_ci
46048c2ecf20Sopenharmony_ci			rx_desc = (struct hal_rx_desc *)msdu->data;
46058c2ecf20Sopenharmony_ci
46068c2ecf20Sopenharmony_ci			rx_pkt_offset = sizeof(struct hal_rx_desc);
46078c2ecf20Sopenharmony_ci			l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(rx_desc);
46088c2ecf20Sopenharmony_ci
46098c2ecf20Sopenharmony_ci			if (is_first_msdu) {
46108c2ecf20Sopenharmony_ci				if (!ath11k_dp_rxdesc_mpdu_valid(rx_desc)) {
46118c2ecf20Sopenharmony_ci					drop_mpdu = true;
46128c2ecf20Sopenharmony_ci					dev_kfree_skb_any(msdu);
46138c2ecf20Sopenharmony_ci					msdu = NULL;
46148c2ecf20Sopenharmony_ci					pmon->mon_last_linkdesc_paddr = paddr;
46158c2ecf20Sopenharmony_ci					goto next_msdu;
46168c2ecf20Sopenharmony_ci				}
46178c2ecf20Sopenharmony_ci
46188c2ecf20Sopenharmony_ci				msdu_ppdu_id =
46198c2ecf20Sopenharmony_ci					ath11k_dp_rxdesc_get_ppduid(rx_desc);
46208c2ecf20Sopenharmony_ci
46218c2ecf20Sopenharmony_ci				if (ath11k_dp_rx_mon_comp_ppduid(msdu_ppdu_id,
46228c2ecf20Sopenharmony_ci								 ppdu_id,
46238c2ecf20Sopenharmony_ci								 &rx_bufs_used)) {
46248c2ecf20Sopenharmony_ci					if (rx_bufs_used) {
46258c2ecf20Sopenharmony_ci						drop_mpdu = true;
46268c2ecf20Sopenharmony_ci						dev_kfree_skb_any(msdu);
46278c2ecf20Sopenharmony_ci						msdu = NULL;
46288c2ecf20Sopenharmony_ci						goto next_msdu;
46298c2ecf20Sopenharmony_ci					}
46308c2ecf20Sopenharmony_ci					return rx_bufs_used;
46318c2ecf20Sopenharmony_ci				}
46328c2ecf20Sopenharmony_ci				pmon->mon_last_linkdesc_paddr = paddr;
46338c2ecf20Sopenharmony_ci				is_first_msdu = false;
46348c2ecf20Sopenharmony_ci			}
46358c2ecf20Sopenharmony_ci			ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i],
46368c2ecf20Sopenharmony_ci						  &is_frag, &total_len,
46378c2ecf20Sopenharmony_ci						  &frag_len, &msdu_cnt);
46388c2ecf20Sopenharmony_ci			rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len;
46398c2ecf20Sopenharmony_ci
46408c2ecf20Sopenharmony_ci			ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size);
46418c2ecf20Sopenharmony_ci
46428c2ecf20Sopenharmony_ci			if (!(*head_msdu))
46438c2ecf20Sopenharmony_ci				*head_msdu = msdu;
46448c2ecf20Sopenharmony_ci			else if (last)
46458c2ecf20Sopenharmony_ci				last->next = msdu;
46468c2ecf20Sopenharmony_ci
46478c2ecf20Sopenharmony_ci			last = msdu;
46488c2ecf20Sopenharmony_cinext_msdu:
46498c2ecf20Sopenharmony_ci			pmon->mon_last_buf_cookie = msdu_list.sw_cookie[i];
46508c2ecf20Sopenharmony_ci			rx_bufs_used++;
46518c2ecf20Sopenharmony_ci			spin_lock_bh(&rx_ring->idr_lock);
46528c2ecf20Sopenharmony_ci			idr_remove(&rx_ring->bufs_idr, buf_id);
46538c2ecf20Sopenharmony_ci			spin_unlock_bh(&rx_ring->idr_lock);
46548c2ecf20Sopenharmony_ci		}
46558c2ecf20Sopenharmony_ci
46568c2ecf20Sopenharmony_ci		ath11k_hal_rx_buf_addr_info_set(rx_link_buf_info, paddr, sw_cookie, rbm);
46578c2ecf20Sopenharmony_ci
46588c2ecf20Sopenharmony_ci		ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, &paddr,
46598c2ecf20Sopenharmony_ci						    &sw_cookie, &rbm,
46608c2ecf20Sopenharmony_ci						    &p_buf_addr_info);
46618c2ecf20Sopenharmony_ci
46628c2ecf20Sopenharmony_ci		if (ar->ab->hw_params.rxdma1_enable) {
46638c2ecf20Sopenharmony_ci			if (ath11k_dp_rx_monitor_link_desc_return(ar,
46648c2ecf20Sopenharmony_ci								  p_last_buf_addr_info,
46658c2ecf20Sopenharmony_ci								  dp->mac_id))
46668c2ecf20Sopenharmony_ci				ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
46678c2ecf20Sopenharmony_ci					   "dp_rx_monitor_link_desc_return failed");
46688c2ecf20Sopenharmony_ci		} else {
46698c2ecf20Sopenharmony_ci			ath11k_dp_rx_link_desc_return(ar->ab, rx_link_buf_info,
46708c2ecf20Sopenharmony_ci						      HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
46718c2ecf20Sopenharmony_ci		}
46728c2ecf20Sopenharmony_ci
46738c2ecf20Sopenharmony_ci		p_last_buf_addr_info = p_buf_addr_info;
46748c2ecf20Sopenharmony_ci
46758c2ecf20Sopenharmony_ci	} while (paddr && msdu_cnt);
46768c2ecf20Sopenharmony_ci
46778c2ecf20Sopenharmony_ci	if (last)
46788c2ecf20Sopenharmony_ci		last->next = NULL;
46798c2ecf20Sopenharmony_ci
46808c2ecf20Sopenharmony_ci	*tail_msdu = msdu;
46818c2ecf20Sopenharmony_ci
46828c2ecf20Sopenharmony_ci	if (msdu_cnt == 0)
46838c2ecf20Sopenharmony_ci		*npackets = 1;
46848c2ecf20Sopenharmony_ci
46858c2ecf20Sopenharmony_ci	return rx_bufs_used;
46868c2ecf20Sopenharmony_ci}
46878c2ecf20Sopenharmony_ci
46888c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_msdus_set_payload(struct sk_buff *msdu)
46898c2ecf20Sopenharmony_ci{
46908c2ecf20Sopenharmony_ci	u32 rx_pkt_offset, l2_hdr_offset;
46918c2ecf20Sopenharmony_ci
46928c2ecf20Sopenharmony_ci	rx_pkt_offset = sizeof(struct hal_rx_desc);
46938c2ecf20Sopenharmony_ci	l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad((struct hal_rx_desc *)msdu->data);
46948c2ecf20Sopenharmony_ci	skb_pull(msdu, rx_pkt_offset + l2_hdr_offset);
46958c2ecf20Sopenharmony_ci}
46968c2ecf20Sopenharmony_ci
46978c2ecf20Sopenharmony_cistatic struct sk_buff *
46988c2ecf20Sopenharmony_ciath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
46998c2ecf20Sopenharmony_ci			    u32 mac_id, struct sk_buff *head_msdu,
47008c2ecf20Sopenharmony_ci			    struct sk_buff *last_msdu,
47018c2ecf20Sopenharmony_ci			    struct ieee80211_rx_status *rxs)
47028c2ecf20Sopenharmony_ci{
47038c2ecf20Sopenharmony_ci	struct sk_buff *msdu, *mpdu_buf, *prev_buf;
47048c2ecf20Sopenharmony_ci	u32 decap_format, wifi_hdr_len;
47058c2ecf20Sopenharmony_ci	struct hal_rx_desc *rx_desc;
47068c2ecf20Sopenharmony_ci	char *hdr_desc;
47078c2ecf20Sopenharmony_ci	u8 *dest;
47088c2ecf20Sopenharmony_ci	struct ieee80211_hdr_3addr *wh;
47098c2ecf20Sopenharmony_ci
47108c2ecf20Sopenharmony_ci	mpdu_buf = NULL;
47118c2ecf20Sopenharmony_ci
47128c2ecf20Sopenharmony_ci	if (!head_msdu)
47138c2ecf20Sopenharmony_ci		goto err_merge_fail;
47148c2ecf20Sopenharmony_ci
47158c2ecf20Sopenharmony_ci	rx_desc = (struct hal_rx_desc *)head_msdu->data;
47168c2ecf20Sopenharmony_ci
47178c2ecf20Sopenharmony_ci	if (ath11k_dp_rxdesc_get_mpdulen_err(rx_desc))
47188c2ecf20Sopenharmony_ci		return NULL;
47198c2ecf20Sopenharmony_ci
47208c2ecf20Sopenharmony_ci	decap_format = ath11k_dp_rxdesc_get_decap_format(rx_desc);
47218c2ecf20Sopenharmony_ci
47228c2ecf20Sopenharmony_ci	ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
47238c2ecf20Sopenharmony_ci
47248c2ecf20Sopenharmony_ci	if (decap_format == DP_RX_DECAP_TYPE_RAW) {
47258c2ecf20Sopenharmony_ci		ath11k_dp_rx_msdus_set_payload(head_msdu);
47268c2ecf20Sopenharmony_ci
47278c2ecf20Sopenharmony_ci		prev_buf = head_msdu;
47288c2ecf20Sopenharmony_ci		msdu = head_msdu->next;
47298c2ecf20Sopenharmony_ci
47308c2ecf20Sopenharmony_ci		while (msdu) {
47318c2ecf20Sopenharmony_ci			ath11k_dp_rx_msdus_set_payload(msdu);
47328c2ecf20Sopenharmony_ci
47338c2ecf20Sopenharmony_ci			prev_buf = msdu;
47348c2ecf20Sopenharmony_ci			msdu = msdu->next;
47358c2ecf20Sopenharmony_ci		}
47368c2ecf20Sopenharmony_ci
47378c2ecf20Sopenharmony_ci		prev_buf->next = NULL;
47388c2ecf20Sopenharmony_ci
47398c2ecf20Sopenharmony_ci		skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN);
47408c2ecf20Sopenharmony_ci	} else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) {
47418c2ecf20Sopenharmony_ci		__le16 qos_field;
47428c2ecf20Sopenharmony_ci		u8 qos_pkt = 0;
47438c2ecf20Sopenharmony_ci
47448c2ecf20Sopenharmony_ci		rx_desc = (struct hal_rx_desc *)head_msdu->data;
47458c2ecf20Sopenharmony_ci		hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc);
47468c2ecf20Sopenharmony_ci
47478c2ecf20Sopenharmony_ci		/* Base size */
47488c2ecf20Sopenharmony_ci		wifi_hdr_len = sizeof(struct ieee80211_hdr_3addr);
47498c2ecf20Sopenharmony_ci		wh = (struct ieee80211_hdr_3addr *)hdr_desc;
47508c2ecf20Sopenharmony_ci
47518c2ecf20Sopenharmony_ci		if (ieee80211_is_data_qos(wh->frame_control)) {
47528c2ecf20Sopenharmony_ci			struct ieee80211_qos_hdr *qwh =
47538c2ecf20Sopenharmony_ci					(struct ieee80211_qos_hdr *)hdr_desc;
47548c2ecf20Sopenharmony_ci
47558c2ecf20Sopenharmony_ci			qos_field = qwh->qos_ctrl;
47568c2ecf20Sopenharmony_ci			qos_pkt = 1;
47578c2ecf20Sopenharmony_ci		}
47588c2ecf20Sopenharmony_ci		msdu = head_msdu;
47598c2ecf20Sopenharmony_ci
47608c2ecf20Sopenharmony_ci		while (msdu) {
47618c2ecf20Sopenharmony_ci			rx_desc = (struct hal_rx_desc *)msdu->data;
47628c2ecf20Sopenharmony_ci			hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc);
47638c2ecf20Sopenharmony_ci
47648c2ecf20Sopenharmony_ci			if (qos_pkt) {
47658c2ecf20Sopenharmony_ci				dest = skb_push(msdu, sizeof(__le16));
47668c2ecf20Sopenharmony_ci				if (!dest)
47678c2ecf20Sopenharmony_ci					goto err_merge_fail;
47688c2ecf20Sopenharmony_ci				memcpy(dest, hdr_desc, wifi_hdr_len);
47698c2ecf20Sopenharmony_ci				memcpy(dest + wifi_hdr_len,
47708c2ecf20Sopenharmony_ci				       (u8 *)&qos_field, sizeof(__le16));
47718c2ecf20Sopenharmony_ci			}
47728c2ecf20Sopenharmony_ci			ath11k_dp_rx_msdus_set_payload(msdu);
47738c2ecf20Sopenharmony_ci			prev_buf = msdu;
47748c2ecf20Sopenharmony_ci			msdu = msdu->next;
47758c2ecf20Sopenharmony_ci		}
47768c2ecf20Sopenharmony_ci		dest = skb_put(prev_buf, HAL_RX_FCS_LEN);
47778c2ecf20Sopenharmony_ci		if (!dest)
47788c2ecf20Sopenharmony_ci			goto err_merge_fail;
47798c2ecf20Sopenharmony_ci
47808c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
47818c2ecf20Sopenharmony_ci			   "mpdu_buf %pK mpdu_buf->len %u",
47828c2ecf20Sopenharmony_ci			   prev_buf, prev_buf->len);
47838c2ecf20Sopenharmony_ci	} else {
47848c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
47858c2ecf20Sopenharmony_ci			   "decap format %d is not supported!\n",
47868c2ecf20Sopenharmony_ci			   decap_format);
47878c2ecf20Sopenharmony_ci		goto err_merge_fail;
47888c2ecf20Sopenharmony_ci	}
47898c2ecf20Sopenharmony_ci
47908c2ecf20Sopenharmony_ci	return head_msdu;
47918c2ecf20Sopenharmony_ci
47928c2ecf20Sopenharmony_cierr_merge_fail:
47938c2ecf20Sopenharmony_ci	if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) {
47948c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
47958c2ecf20Sopenharmony_ci			   "err_merge_fail mpdu_buf %pK", mpdu_buf);
47968c2ecf20Sopenharmony_ci		/* Free the head buffer */
47978c2ecf20Sopenharmony_ci		dev_kfree_skb_any(mpdu_buf);
47988c2ecf20Sopenharmony_ci	}
47998c2ecf20Sopenharmony_ci	return NULL;
48008c2ecf20Sopenharmony_ci}
48018c2ecf20Sopenharmony_ci
48028c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id,
48038c2ecf20Sopenharmony_ci				    struct sk_buff *head_msdu,
48048c2ecf20Sopenharmony_ci				    struct sk_buff *tail_msdu,
48058c2ecf20Sopenharmony_ci				    struct napi_struct *napi)
48068c2ecf20Sopenharmony_ci{
48078c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
48088c2ecf20Sopenharmony_ci	struct sk_buff *mon_skb, *skb_next, *header;
48098c2ecf20Sopenharmony_ci	struct ieee80211_rx_status *rxs = &dp->rx_status, *status;
48108c2ecf20Sopenharmony_ci
48118c2ecf20Sopenharmony_ci	mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu,
48128c2ecf20Sopenharmony_ci					      tail_msdu, rxs);
48138c2ecf20Sopenharmony_ci
48148c2ecf20Sopenharmony_ci	if (!mon_skb)
48158c2ecf20Sopenharmony_ci		goto mon_deliver_fail;
48168c2ecf20Sopenharmony_ci
48178c2ecf20Sopenharmony_ci	header = mon_skb;
48188c2ecf20Sopenharmony_ci
48198c2ecf20Sopenharmony_ci	rxs->flag = 0;
48208c2ecf20Sopenharmony_ci	do {
48218c2ecf20Sopenharmony_ci		skb_next = mon_skb->next;
48228c2ecf20Sopenharmony_ci		if (!skb_next)
48238c2ecf20Sopenharmony_ci			rxs->flag &= ~RX_FLAG_AMSDU_MORE;
48248c2ecf20Sopenharmony_ci		else
48258c2ecf20Sopenharmony_ci			rxs->flag |= RX_FLAG_AMSDU_MORE;
48268c2ecf20Sopenharmony_ci
48278c2ecf20Sopenharmony_ci		if (mon_skb == header) {
48288c2ecf20Sopenharmony_ci			header = NULL;
48298c2ecf20Sopenharmony_ci			rxs->flag &= ~RX_FLAG_ALLOW_SAME_PN;
48308c2ecf20Sopenharmony_ci		} else {
48318c2ecf20Sopenharmony_ci			rxs->flag |= RX_FLAG_ALLOW_SAME_PN;
48328c2ecf20Sopenharmony_ci		}
48338c2ecf20Sopenharmony_ci		rxs->flag |= RX_FLAG_ONLY_MONITOR;
48348c2ecf20Sopenharmony_ci
48358c2ecf20Sopenharmony_ci		status = IEEE80211_SKB_RXCB(mon_skb);
48368c2ecf20Sopenharmony_ci		*status = *rxs;
48378c2ecf20Sopenharmony_ci
48388c2ecf20Sopenharmony_ci		ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb);
48398c2ecf20Sopenharmony_ci		mon_skb = skb_next;
48408c2ecf20Sopenharmony_ci	} while (mon_skb);
48418c2ecf20Sopenharmony_ci	rxs->flag = 0;
48428c2ecf20Sopenharmony_ci
48438c2ecf20Sopenharmony_ci	return 0;
48448c2ecf20Sopenharmony_ci
48458c2ecf20Sopenharmony_cimon_deliver_fail:
48468c2ecf20Sopenharmony_ci	mon_skb = head_msdu;
48478c2ecf20Sopenharmony_ci	while (mon_skb) {
48488c2ecf20Sopenharmony_ci		skb_next = mon_skb->next;
48498c2ecf20Sopenharmony_ci		dev_kfree_skb_any(mon_skb);
48508c2ecf20Sopenharmony_ci		mon_skb = skb_next;
48518c2ecf20Sopenharmony_ci	}
48528c2ecf20Sopenharmony_ci	return -EINVAL;
48538c2ecf20Sopenharmony_ci}
48548c2ecf20Sopenharmony_ci
48558c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id,
48568c2ecf20Sopenharmony_ci					  u32 quota, struct napi_struct *napi)
48578c2ecf20Sopenharmony_ci{
48588c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
48598c2ecf20Sopenharmony_ci	struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
48608c2ecf20Sopenharmony_ci	void *ring_entry;
48618c2ecf20Sopenharmony_ci	void *mon_dst_srng;
48628c2ecf20Sopenharmony_ci	u32 ppdu_id;
48638c2ecf20Sopenharmony_ci	u32 rx_bufs_used;
48648c2ecf20Sopenharmony_ci	u32 ring_id;
48658c2ecf20Sopenharmony_ci	struct ath11k_pdev_mon_stats *rx_mon_stats;
48668c2ecf20Sopenharmony_ci	u32	 npackets = 0;
48678c2ecf20Sopenharmony_ci
48688c2ecf20Sopenharmony_ci	if (ar->ab->hw_params.rxdma1_enable)
48698c2ecf20Sopenharmony_ci		ring_id = dp->rxdma_mon_dst_ring.ring_id;
48708c2ecf20Sopenharmony_ci	else
48718c2ecf20Sopenharmony_ci		ring_id = dp->rxdma_err_dst_ring[mac_id].ring_id;
48728c2ecf20Sopenharmony_ci
48738c2ecf20Sopenharmony_ci	mon_dst_srng = &ar->ab->hal.srng_list[ring_id];
48748c2ecf20Sopenharmony_ci
48758c2ecf20Sopenharmony_ci	if (!mon_dst_srng) {
48768c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
48778c2ecf20Sopenharmony_ci			    "HAL Monitor Destination Ring Init Failed -- %pK",
48788c2ecf20Sopenharmony_ci			    mon_dst_srng);
48798c2ecf20Sopenharmony_ci		return;
48808c2ecf20Sopenharmony_ci	}
48818c2ecf20Sopenharmony_ci
48828c2ecf20Sopenharmony_ci	spin_lock_bh(&pmon->mon_lock);
48838c2ecf20Sopenharmony_ci
48848c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng);
48858c2ecf20Sopenharmony_ci
48868c2ecf20Sopenharmony_ci	ppdu_id = pmon->mon_ppdu_info.ppdu_id;
48878c2ecf20Sopenharmony_ci	rx_bufs_used = 0;
48888c2ecf20Sopenharmony_ci	rx_mon_stats = &pmon->rx_mon_stats;
48898c2ecf20Sopenharmony_ci
48908c2ecf20Sopenharmony_ci	while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) {
48918c2ecf20Sopenharmony_ci		struct sk_buff *head_msdu, *tail_msdu;
48928c2ecf20Sopenharmony_ci
48938c2ecf20Sopenharmony_ci		head_msdu = NULL;
48948c2ecf20Sopenharmony_ci		tail_msdu = NULL;
48958c2ecf20Sopenharmony_ci
48968c2ecf20Sopenharmony_ci		rx_bufs_used += ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry,
48978c2ecf20Sopenharmony_ci							  &head_msdu,
48988c2ecf20Sopenharmony_ci							  &tail_msdu,
48998c2ecf20Sopenharmony_ci							  &npackets, &ppdu_id);
49008c2ecf20Sopenharmony_ci
49018c2ecf20Sopenharmony_ci		if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) {
49028c2ecf20Sopenharmony_ci			pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
49038c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
49048c2ecf20Sopenharmony_ci				   "dest_rx: new ppdu_id %x != status ppdu_id %x",
49058c2ecf20Sopenharmony_ci				   ppdu_id, pmon->mon_ppdu_info.ppdu_id);
49068c2ecf20Sopenharmony_ci			break;
49078c2ecf20Sopenharmony_ci		}
49088c2ecf20Sopenharmony_ci		if (head_msdu && tail_msdu) {
49098c2ecf20Sopenharmony_ci			ath11k_dp_rx_mon_deliver(ar, dp->mac_id, head_msdu,
49108c2ecf20Sopenharmony_ci						 tail_msdu, napi);
49118c2ecf20Sopenharmony_ci			rx_mon_stats->dest_mpdu_done++;
49128c2ecf20Sopenharmony_ci		}
49138c2ecf20Sopenharmony_ci
49148c2ecf20Sopenharmony_ci		ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab,
49158c2ecf20Sopenharmony_ci								mon_dst_srng);
49168c2ecf20Sopenharmony_ci	}
49178c2ecf20Sopenharmony_ci	ath11k_hal_srng_access_end(ar->ab, mon_dst_srng);
49188c2ecf20Sopenharmony_ci
49198c2ecf20Sopenharmony_ci	spin_unlock_bh(&pmon->mon_lock);
49208c2ecf20Sopenharmony_ci
49218c2ecf20Sopenharmony_ci	if (rx_bufs_used) {
49228c2ecf20Sopenharmony_ci		rx_mon_stats->dest_ppdu_done++;
49238c2ecf20Sopenharmony_ci		if (ar->ab->hw_params.rxdma1_enable)
49248c2ecf20Sopenharmony_ci			ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id,
49258c2ecf20Sopenharmony_ci						   &dp->rxdma_mon_buf_ring,
49268c2ecf20Sopenharmony_ci						   rx_bufs_used,
49278c2ecf20Sopenharmony_ci						   HAL_RX_BUF_RBM_SW3_BM);
49288c2ecf20Sopenharmony_ci		else
49298c2ecf20Sopenharmony_ci			ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id,
49308c2ecf20Sopenharmony_ci						   &dp->rx_refill_buf_ring,
49318c2ecf20Sopenharmony_ci						   rx_bufs_used,
49328c2ecf20Sopenharmony_ci						   HAL_RX_BUF_RBM_SW3_BM);
49338c2ecf20Sopenharmony_ci	}
49348c2ecf20Sopenharmony_ci}
49358c2ecf20Sopenharmony_ci
49368c2ecf20Sopenharmony_cistatic void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar,
49378c2ecf20Sopenharmony_ci						int mac_id, u32 quota,
49388c2ecf20Sopenharmony_ci						struct napi_struct *napi)
49398c2ecf20Sopenharmony_ci{
49408c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
49418c2ecf20Sopenharmony_ci	struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
49428c2ecf20Sopenharmony_ci	struct hal_rx_mon_ppdu_info *ppdu_info;
49438c2ecf20Sopenharmony_ci	struct sk_buff *status_skb;
49448c2ecf20Sopenharmony_ci	u32 tlv_status = HAL_TLV_STATUS_BUF_DONE;
49458c2ecf20Sopenharmony_ci	struct ath11k_pdev_mon_stats *rx_mon_stats;
49468c2ecf20Sopenharmony_ci
49478c2ecf20Sopenharmony_ci	ppdu_info = &pmon->mon_ppdu_info;
49488c2ecf20Sopenharmony_ci	rx_mon_stats = &pmon->rx_mon_stats;
49498c2ecf20Sopenharmony_ci
49508c2ecf20Sopenharmony_ci	if (pmon->mon_ppdu_status != DP_PPDU_STATUS_START)
49518c2ecf20Sopenharmony_ci		return;
49528c2ecf20Sopenharmony_ci
49538c2ecf20Sopenharmony_ci	while (!skb_queue_empty(&pmon->rx_status_q)) {
49548c2ecf20Sopenharmony_ci		status_skb = skb_dequeue(&pmon->rx_status_q);
49558c2ecf20Sopenharmony_ci
49568c2ecf20Sopenharmony_ci		tlv_status = ath11k_hal_rx_parse_mon_status(ar->ab, ppdu_info,
49578c2ecf20Sopenharmony_ci							    status_skb);
49588c2ecf20Sopenharmony_ci		if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) {
49598c2ecf20Sopenharmony_ci			rx_mon_stats->status_ppdu_done++;
49608c2ecf20Sopenharmony_ci			pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE;
49618c2ecf20Sopenharmony_ci			ath11k_dp_rx_mon_dest_process(ar, mac_id, quota, napi);
49628c2ecf20Sopenharmony_ci			pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
49638c2ecf20Sopenharmony_ci		}
49648c2ecf20Sopenharmony_ci		dev_kfree_skb_any(status_skb);
49658c2ecf20Sopenharmony_ci	}
49668c2ecf20Sopenharmony_ci}
49678c2ecf20Sopenharmony_ci
49688c2ecf20Sopenharmony_cistatic int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id,
49698c2ecf20Sopenharmony_ci				    struct napi_struct *napi, int budget)
49708c2ecf20Sopenharmony_ci{
49718c2ecf20Sopenharmony_ci	struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id);
49728c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
49738c2ecf20Sopenharmony_ci	struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
49748c2ecf20Sopenharmony_ci	int num_buffs_reaped = 0;
49758c2ecf20Sopenharmony_ci
49768c2ecf20Sopenharmony_ci	num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ar->ab, mac_id, &budget,
49778c2ecf20Sopenharmony_ci							     &pmon->rx_status_q);
49788c2ecf20Sopenharmony_ci	if (num_buffs_reaped)
49798c2ecf20Sopenharmony_ci		ath11k_dp_rx_mon_status_process_tlv(ar, mac_id, budget, napi);
49808c2ecf20Sopenharmony_ci
49818c2ecf20Sopenharmony_ci	return num_buffs_reaped;
49828c2ecf20Sopenharmony_ci}
49838c2ecf20Sopenharmony_ci
49848c2ecf20Sopenharmony_ciint ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id,
49858c2ecf20Sopenharmony_ci				   struct napi_struct *napi, int budget)
49868c2ecf20Sopenharmony_ci{
49878c2ecf20Sopenharmony_ci	struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id);
49888c2ecf20Sopenharmony_ci	int ret = 0;
49898c2ecf20Sopenharmony_ci
49908c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags))
49918c2ecf20Sopenharmony_ci		ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget);
49928c2ecf20Sopenharmony_ci	else
49938c2ecf20Sopenharmony_ci		ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget);
49948c2ecf20Sopenharmony_ci	return ret;
49958c2ecf20Sopenharmony_ci}
49968c2ecf20Sopenharmony_ci
49978c2ecf20Sopenharmony_cistatic int ath11k_dp_rx_pdev_mon_status_attach(struct ath11k *ar)
49988c2ecf20Sopenharmony_ci{
49998c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
50008c2ecf20Sopenharmony_ci	struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
50018c2ecf20Sopenharmony_ci
50028c2ecf20Sopenharmony_ci	skb_queue_head_init(&pmon->rx_status_q);
50038c2ecf20Sopenharmony_ci
50048c2ecf20Sopenharmony_ci	pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
50058c2ecf20Sopenharmony_ci
50068c2ecf20Sopenharmony_ci	memset(&pmon->rx_mon_stats, 0,
50078c2ecf20Sopenharmony_ci	       sizeof(pmon->rx_mon_stats));
50088c2ecf20Sopenharmony_ci	return 0;
50098c2ecf20Sopenharmony_ci}
50108c2ecf20Sopenharmony_ci
50118c2ecf20Sopenharmony_ciint ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar)
50128c2ecf20Sopenharmony_ci{
50138c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
50148c2ecf20Sopenharmony_ci	struct ath11k_mon_data *pmon = &dp->mon_data;
50158c2ecf20Sopenharmony_ci	struct hal_srng *mon_desc_srng = NULL;
50168c2ecf20Sopenharmony_ci	struct dp_srng *dp_srng;
50178c2ecf20Sopenharmony_ci	int ret = 0;
50188c2ecf20Sopenharmony_ci	u32 n_link_desc = 0;
50198c2ecf20Sopenharmony_ci
50208c2ecf20Sopenharmony_ci	ret = ath11k_dp_rx_pdev_mon_status_attach(ar);
50218c2ecf20Sopenharmony_ci	if (ret) {
50228c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "pdev_mon_status_attach() failed");
50238c2ecf20Sopenharmony_ci		return ret;
50248c2ecf20Sopenharmony_ci	}
50258c2ecf20Sopenharmony_ci
50268c2ecf20Sopenharmony_ci	/* if rxdma1_enable is false, no need to setup
50278c2ecf20Sopenharmony_ci	 * rxdma_mon_desc_ring.
50288c2ecf20Sopenharmony_ci	 */
50298c2ecf20Sopenharmony_ci	if (!ar->ab->hw_params.rxdma1_enable)
50308c2ecf20Sopenharmony_ci		return 0;
50318c2ecf20Sopenharmony_ci
50328c2ecf20Sopenharmony_ci	dp_srng = &dp->rxdma_mon_desc_ring;
50338c2ecf20Sopenharmony_ci	n_link_desc = dp_srng->size /
50348c2ecf20Sopenharmony_ci		ath11k_hal_srng_get_entrysize(ar->ab, HAL_RXDMA_MONITOR_DESC);
50358c2ecf20Sopenharmony_ci	mon_desc_srng =
50368c2ecf20Sopenharmony_ci		&ar->ab->hal.srng_list[dp->rxdma_mon_desc_ring.ring_id];
50378c2ecf20Sopenharmony_ci
50388c2ecf20Sopenharmony_ci	ret = ath11k_dp_link_desc_setup(ar->ab, pmon->link_desc_banks,
50398c2ecf20Sopenharmony_ci					HAL_RXDMA_MONITOR_DESC, mon_desc_srng,
50408c2ecf20Sopenharmony_ci					n_link_desc);
50418c2ecf20Sopenharmony_ci	if (ret) {
50428c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "mon_link_desc_pool_setup() failed");
50438c2ecf20Sopenharmony_ci		return ret;
50448c2ecf20Sopenharmony_ci	}
50458c2ecf20Sopenharmony_ci	pmon->mon_last_linkdesc_paddr = 0;
50468c2ecf20Sopenharmony_ci	pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1;
50478c2ecf20Sopenharmony_ci	spin_lock_init(&pmon->mon_lock);
50488c2ecf20Sopenharmony_ci
50498c2ecf20Sopenharmony_ci	return 0;
50508c2ecf20Sopenharmony_ci}
50518c2ecf20Sopenharmony_ci
50528c2ecf20Sopenharmony_cistatic int ath11k_dp_mon_link_free(struct ath11k *ar)
50538c2ecf20Sopenharmony_ci{
50548c2ecf20Sopenharmony_ci	struct ath11k_pdev_dp *dp = &ar->dp;
50558c2ecf20Sopenharmony_ci	struct ath11k_mon_data *pmon = &dp->mon_data;
50568c2ecf20Sopenharmony_ci
50578c2ecf20Sopenharmony_ci	ath11k_dp_link_desc_cleanup(ar->ab, pmon->link_desc_banks,
50588c2ecf20Sopenharmony_ci				    HAL_RXDMA_MONITOR_DESC,
50598c2ecf20Sopenharmony_ci				    &dp->rxdma_mon_desc_ring);
50608c2ecf20Sopenharmony_ci	return 0;
50618c2ecf20Sopenharmony_ci}
50628c2ecf20Sopenharmony_ci
50638c2ecf20Sopenharmony_ciint ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar)
50648c2ecf20Sopenharmony_ci{
50658c2ecf20Sopenharmony_ci	ath11k_dp_mon_link_free(ar);
50668c2ecf20Sopenharmony_ci	return 0;
50678c2ecf20Sopenharmony_ci}
5068